Michał Simon
Michał Simon

Reputation: 21

C++ derived class overloaded function (with std::function argument) not visible

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

Answers (2)

Jans
Jans

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

Vittorio Romeo
Vittorio Romeo

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

Related Questions