Why does "template<typename T> ... function<T(int)>" not match "int(&)(int)" implicitly?

S

Steve Hicks

Hi,

I'm using g++-4.3.3 and trying to compile the following minimal code

#include <tr1/functional>
using std::tr1::function;
int foo(int x) { return x+1; }
template <typename T> T bar(function<T(int)> f,int a) { return f(a); }
int main() { return bar(foo,1); }

and I get the error "no matching function for call to ‘bar(int (&)
(int), int)". It works if I change bar to take a function<int(int)>.
It also works if I add an explicit cast, as in bar((function<int(int)>)
foo,1). And I know the constructor is implicit, since I can say
"function<int(int)> foo_f = foo; bar(foo_f,1);" and it works just
fine. My code also fails when using a function object (with a member
int operator()(int)).

But I'm trying to make a function similar to bind, where you can pass
any sort of function reference/pointer/object/etc without any explicit
casts, and it "just works" (in fact, I'd rather take a function<T(A)>
with both types templated, but one thing at a time...)

I looked at gcc's tr1_impl/functional header and see that function
objects and bind take all sorts of scary-looking variadic templates,
and the entire functor input is a single template _Functor, rather
than an explicit function<T(A)>. But since function<> does have these
implicit constructors, is there any way to help out the compiler in
figuring out what's so obvious to a human? It seems like matching the
argument types is much more straightforward if I can just specify the
same A in both arguments bar(function<T(A)>,A)... I wouldn't even know
how to start making sense of it when the functor and the argument
types are separate templates. How can I go about doing that, if it's
actually necessary?

Thanks,
Steve
 
V

Vladimir Jovic

Steve said:
Hi,

I'm using g++-4.3.3 and trying to compile the following minimal code

#include <tr1/functional>
using std::tr1::function;
int foo(int x) { return x+1; }
template <typename T> T bar(function<T(int)> f,int a) { return f(a); }
int main() { return bar(foo,1); }

This fixes it:
int main() { return bar< int >(foo,1); }

In your example, type T can not be deduced.

<...>
 
S

SG

Steve said:
#include <tr1/functional>
using std::tr1::function;
int foo(int x) { return x+1; }
template <typename T> T bar(function<T(int)> f,int a) { return f(a); }
int main() { return bar(foo,1); }

and I get the error "no matching function for call to ‘bar(int (&)
(int), int)".  It works if I change bar to take a function<int(int)>.

Right. The difference is that T doesn't have to be deduced anymore.
It also works if I add an explicit cast, as in bar((function<int(int)>)
foo,1).

Right. In this case (the type matches exactly) the compiler is able to
deduce T. You can also write bar<int>(foo,1) -- specifying T so no
deduction has to be performed. You could even write bar<void>(foo,1)
or bar<double>(foo,1) as far as I can tell. So the number of possible
type parameters with successfull template instantiations is even
greater than one. What's the "right" one?
And I know the constructor is implicit, since I can say
"function<int(int)> foo_f  = foo; bar(foo_f,1);" and it works just
fine.  My code also fails when using a function object (with a member
int operator()(int)).

Right. Because the types don't match. Your function object is not a
std::function and therefore type deduction of T won't work. Type
deduction only considers array-to-pointer, function-to-pointer, cv
qualification, and derived-to-base conversions. Nothing else. No other
implicit conversions. This is a good thing, actually. ;-)
But I'm trying to make a function similar to bind, where you can pass
any sort of function reference/pointer/object/etc without any explicit
casts, and it "just works" (in fact, I'd rather take a function<T(A)>
with both types templated, but one thing at a time...)

You could try to use overloading and SFINAE to "detect the correct T"
for non-function<> objects:

template <typename T>
T bar(function<T(int)> f,int a)
{
... your code ...
}

template <typename Func>
inline typename result_of<Func(int)>::type
bar(Func const& fun, int a)
{
typedef typename result_of<Func(int)>::type ret_t;
return bar<ret_t>(fun,a); // relay
}

The first function template accepts function<T(int)> objects directly
for some T (if T can be deduced or is explicitly given and an implicit
conversion exists. The second function takes any functor, tries to
detect the return type when given an int parameter and relays to the
first function. Wrapping the functor in a function<> object is done
implicitly since the type parameter is specified and doesn't need to
be deduced. -- I havn't tested the code above, though.
I looked at gcc's tr1_impl/functional header and see that function
objects and bind take all sorts of scary-looking variadic templates,
and the entire functor input is a single template _Functor, rather
than an explicit function<T(A)>.

Yeah, why not? If you don't want the code bloat and don't mind the
virtual function call overhead you can always try to wrap the functor
manually in a function said:
 But since function<> does have these
implicit constructors, is there any way to help out the compiler in
figuring out what's so obvious to a human?

See above.

Cheers,
SG
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,906
Latest member
SkinfixSkintag

Latest Threads

Top