Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Question on type deduction

4 views
Skip to first unread message

francis_r

unread,
Jul 11, 2006, 4:42:19 PM7/11/06
to
Following very simplified code will illustrate my problem:


void Augment( int& outNumber )
{
outNumber++;
}

template< typename ReturnType, typename Type1 >
ReturnType ExecuteFunction( ReturnType (*inFunction)( Type1 ), Type1
inArg1 )
{
return inFunction( inArg1 );
}

int main()
{
int theNumber = 10;
ExecuteFunction( Augment, theNumber ); // <-- compiler error
ExecuteFunction< void, int& >( Augment, theNumber ); // compiles OK
}

Compiler error goes as follows:
function call
ExecuteFunction({lval} void (int &), {lval} int)' does not match
'ExecuteFunction<...>(__T0 (*)(__T1), __T1)'
on line 435 ExecuteFunction( Augment, theNumber );

It seems that the second argument (theNumber) is not passed by
reference even though the Augment requests int& explicitely.

Is there a way I can rewrite the function ExecuteFunction so that I can
call it without having to explicitely specify it's template parameters?
If so, how?

Thanks in advance for all helpful feedback.

Kind regards,
Francis


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Vladimir Marko

unread,
Jul 12, 2006, 4:46:23 PM7/12/06
to
francis_r wrote:
> void Augment( int& outNumber )
> {
> outNumber++;
> }
>
> template< typename ReturnType, typename Type1 >
> ReturnType ExecuteFunction( ReturnType (*inFunction)( Type1 ), Type1
> inArg1 )
> {
> return inFunction( inArg1 );
> }
>
> int main()
> {
> int theNumber = 10;
> ExecuteFunction( Augment, theNumber ); // <-- compiler error
> ExecuteFunction< void, int& >( Augment, theNumber ); // compiles OK
> }

The compiler deduces the parameters from each of the arguments
independently. From the first one, it deduces ReturnType=void and
Type1=int& ; from the second one it can only deduce Type1=int.
These two results are incompatible, so the deduction fails.

> It seems that the second argument (theNumber) is not passed by
> reference even though the Augment requests int& explicitely.
>
> Is there a way I can rewrite the function ExecuteFunction so that I can
> call it without having to explicitely specify it's template parameters?
> If so, how?

Yes, try this:

template <typename T>
struct identity { typedef T type; };

template <typename R,typename A>
R exec(R (*fn)(A),typename identity<A>::type a) { return fn(a); }

void foo(int& a) { }

int main(){
int i=0;
exec(foo,i);
}

Here the second parameter of exec does not participate in the
deduction at all.

Cheers,
Vladimir Marko

Frederick Gotham

unread,
Jul 12, 2006, 6:19:02 PM7/12/06
to
francis_r posted:


> Is there a way I can rewrite the function ExecuteFunction so that I can
> call it without having to explicitely specify it's template parameters?
> If so, how?

void Augment( int &outNumber )
{

++outNumber;
}

template<class ReturnType,class Type1>
ReturnType ExecuteFunction(ReturnType (*inFunction)(Type1&), Type1 &inArg1)
{
return inFunction(inArg1);
}

int main()
{
int theNumber = 10;
ExecuteFunction( Augment, theNumber );
}


--

Frederick Gotham

Thomas Maeder

unread,
Jul 12, 2006, 6:28:41 PM7/12/06
to

"francis_r" <francis....@gmail.com> writes:

> void Augment( int& outNumber )

> {

> outNumber++;

> }

>

> template< typename ReturnType, typename Type1 >

> ReturnType ExecuteFunction( ReturnType (*inFunction)( Type1 ), Type1

> inArg1 )

> {

> return inFunction( inArg1 );

> }

>

> int main()

> {

> int theNumber = 10;

> ExecuteFunction( Augment, theNumber ); // <-- compiler error

> ExecuteFunction< void, int& >( Augment, theNumber ); // compiles OK

> }

>

> Compiler error goes as follows:

> function call

> ExecuteFunction({lval} void (int &), {lval} int)' does not match

> 'ExecuteFunction<...>(__T0 (*)(__T1), __T1)'

> on line 435 ExecuteFunction( Augment, theNumber );

>

> It seems that the second argument (theNumber) is not passed by

> reference even though the Augment requests int& explicitely.

The two decisions take place in the reverse order. First, the types of

the arguments are established, then the available ExecuteFunction

overloads are attempted to be matched.

> Is there a way I can rewrite the function ExecuteFunction so that I

> can call it without having to explicitely specify it's template

> parameters? If so, how?

You could add an overload

template <typename ReturnType, typename Type1>

ReturnType ExecuteFunction(ReturnType (*inFunction)(Type1 &),

Type1 &inArg1)

{

return inFunction(inArg1);

Carl Barron

unread,
Jul 12, 2006, 6:29:51 PM7/12/06
to
In article <1152610779....@75g2000cwc.googlegroups.com>,
francis_r <francis....@gmail.com> wrote:

> Following very simplified code will illustrate my problem:
>
>
> void Augment( int& outNumber )
> {
> outNumber++;
> }
>
> template< typename ReturnType, typename Type1 >
> ReturnType ExecuteFunction( ReturnType (*inFunction)( Type1 ), Type1
> inArg1 )
> {
> return inFunction( inArg1 );
> }

> Is there a way I can rewrite the function ExecuteFunction so that I can


> call it without having to explicitely specify it's template parameters?
>

template <class R,class T>
R exec_function(R (*f)(T &),T &x)
{
return f(x);
}

template <class R,class T>
R exec_function(R (*f)(T),T x)
{
return f(x);

kernel0

unread,
Jul 12, 2006, 6:30:46 PM7/12/06
to
change template function signature

from
------------------------------------------------------------------------------------------------------------


template< typename ReturnType, typename Type1 >
ReturnType ExecuteFunction( ReturnType (*inFunction)( Type1 ), Type1
inArg1 )

to

template< typename ReturnType, typename Type1 >

ReturnType ExecuteFunction( ReturnType (*inFunction)( Type1& ), Type1
inArg1 )

Owen

unread,
Jul 12, 2006, 6:32:08 PM7/12/06
to

francis_r:

>
> void Augment( int& outNumber )
> {
> outNumber++;
> }
> int main()
> {
> int theNumber = 10;
> ExecuteFunction( Augment, theNumber ); // <-- compiler error
> ExecuteFunction< void, int& >( Augment, theNumber ); // compiles OK
> }
>

void Augment( int* outNumber )
{
(*outNumber)++;


}
int main()
{
int theNumber = 10;

ExecuteFunction( Augment, &theNumber ); // <-- compiler error
ExecuteFunction< void, int* >( Augment, &theNumber ); // compiles
OK
}

[...]

Ian Wakeling

unread,
Jul 12, 2006, 6:50:36 PM7/12/06
to
francis_r wrote:

Look at the types involved in the call that doesn't work:


> ExecuteFunction( Augment, theNumber ); // <-- compiler error

Augment is a pointer to a function that takes an int& and returns void.
theNumber is an int.

So, the generated instance of ExecuteFunction will look like this:

void ExecuteFunction( void (*inFunction)( int& ), int inArg1 )
{
return inFunction( inArg1 );
}

Hopefully the problem is now obvious: inArg1 is an int, which cannot be
converted to an int& for the call to inFunction.

To be honest, the use of an int& is not really good style anyway: given the
calling site, how is the poor maintenance programmer supposed to know that
calling ExecuteFunction() is going to alter the value of theNumber? Yes,
they can work it out by looking at the definition of Augment, but you are
just setting traps for the unwary, which won't earn you any friends when
the pressure is on to iron out the last few bugs and ship the product.

The good news is that if you remove the use of int&, you not only make the
code more obvious, you solve the compilation problem as well. Either
replace the int& with an int*, so that the calling site becomes

ExecuteFunction( Augment, &theNumber );

or adopt a more value based approach (which will sit better with the STL)
and change Augment to return the altered value instead:

int Augment( int num )
{
return( num + 1 );
}

This also yields a more readable calling site:
int theNumber = 10;
theNumber = ExecuteFunction( Augment, theNumber );

Ian


-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

Przemyslaw Szymanski

unread,
Jul 12, 2006, 7:03:49 PM7/12/06
to
francis_r wrote:
> Following very simplified code will illustrate my problem:
>
>
> void Augment( int& outNumber )
> {
> outNumber++;
> }
>
> template< typename ReturnType, typename Type1 >
> ReturnType ExecuteFunction( ReturnType (*inFunction)( Type1 ), Type1
> inArg1 )
> {
> return inFunction( inArg1 );
> }
>
> int main()
> {
> int theNumber = 10;
> ExecuteFunction( Augment, theNumber ); // <-- compiler error
> ExecuteFunction< void, int& >( Augment, theNumber ); // compiles OK
> }
>
> Compiler error goes as follows:
> function call
> ExecuteFunction({lval} void (int &), {lval} int)' does not match
> 'ExecuteFunction<...>(__T0 (*)(__T1), __T1)'
> on line 435 ExecuteFunction( Augment, theNumber );
>
> It seems that the second argument (theNumber) is not passed by
> reference even though the Augment requests int& explicitely.
>
> Is there a way I can rewrite the function ExecuteFunction so that I can
> call it without having to explicitely specify it's template parameters?
> If so, how?

The problem is that argument deduction mechanism is trying to deduce
the actual type of Type1 template parameter from both actual parameters
of ExecuteFunction instantiation. From the first argument it is 'int &'
but from the second it's 'int', so the deduction fails. You could try
to introduce a nondeducible context for the second parameter which will
limit deduction to the first argument only:

template <typename T>
struct wrapper
{
typedef T type;
};

template< typename ReturnType, typename Type1 >

ReturnType ExecuteFunction( ReturnType (*inFunction)( Type1 ), typename
wrapper<Type1>::type inArg1 )
{
return inFunction( inArg1 );
}

Regards,
Przemek.

0 new messages