Reputation: 21
Let me illustrate my question with following example. Suppose we have a base class that defines method Exec that takes one argument of any type (template). The method Exec calls then method Call that has been overloaded to take as an argument an std::function object with different parameters.
Now suppose we have a derived class that inherits after Base and overloads Exec so it takes as an argument yet another std::function object (with different argument set).
Something like:
struct Base
{
template<typename Func>
static void Exec( Func func )
{
Call( func );
}
static void Call( std::function<void(void)> func )
{
func();
}
/*other definitions of Call for other std::functions*/
};
struct Derived : public Base
{
using Base::Exec;
static void Exec( std::function<void(int)> func )
{
func( 10 );
}
};
Now suppose we want to call:
Derived::Exec( []( int i ){std::cout << i << std::endl;} );
this will give following compilation error (I tried with g++ 4.8.5 and 8.1.1):
error: no matching function for call to 'Base::Call(main(int, char**)::<lambda(int)>&)'
My question is: why does the compiler not see the definition of Exec
in Derived class (void Derived::Exec( std::function<void(int)> func )
)?
I would expect that during overload resolution the Derived::Exec
will be chosen as it is most appropriate for the given argument:
[]( int i ){std::cout << i << std::endl;}
What am I missing?
Upvotes: 2
Views: 152
Reputation: 11250
The lambda []( int i ){std::cout << i << std::endl;}
is convertible to std::function<void(int)>
not to std::function<void(void)>
.
Even when the template function in Base is being selected because of perfect match, inside of it you're passing func
to Base::Call
that accept something convertible to std::function<void(void)>
, and the lambda is not. Derived::Call
is never selected because of static dispatch, that's the reason of the error.
Upvotes: 0
Reputation: 93314
Lambda expressions produce closures that have anonymous and unique types. These types are completely unrelated from std::function
.
Your template
is a better match as it can deduce the exact type of the closure. Invoking the non-template
overload would require an std::function
instance to be created from the closure (not an exact match).
Upvotes: 8