C ++派生类重载函数(带有std :: function参数)不可见

时间:2018-09-27 13:25:19

标签: c++ templates

让我通过以下示例说明我的问题。假设我们有一个基类定义了方法 Exec ,该方法接受任何类型的参数(模板)。方法 Exec 调用,然后调用方法 Call ,该方法已重载以将带有不同参数的std :: function对象作为参数。

现在假设我们有一个派生类,该派生类在 Base 之后继承并重载 Exec ,因此它将另一个std :: function对象作为参数(具有不同的参数集)

类似的东西:

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 );
  }
};

现在假设我们要致电:

Derived::Exec( []( int i ){std::cout << i << std::endl;} );

这将产生以下编译错误(我尝试使用g ++ 4.8.5和8.1.1):

error: no matching function for call to 'Base::Call(main(int, char**)::<lambda(int)>&)'

我的问题是:为什么编译器在派生类(Exec)中看不到void Derived::Exec( std::function<void(int)> func )的定义? 我希望在重载解析期间会选择Derived::Exec,因为它最适合给定的参数:

 []( int i ){std::cout << i << std::endl;}

我想念什么?

2 个答案:

答案 0 :(得分:8)

Lambda表达式生成具有匿名唯一类型的闭包。这些类型与std::function完全无关。

您的template是更好的匹配,因为它可以推断出 closure 的确切类型。调用非template重载将需要从 closure 中创建一个std::function实例(不是完全匹配)。

答案 1 :(得分:0)

λ[]( int i ){std::cout << i << std::endl;}可以转换为std::function<void(int)>而不是std::function<void(void)>

即使由于完美匹配而选择了Base中的模板功能时,在其中也将func传递给Base::Call并接受可转换为std::function<void(void)>的内容和lambda不是。由于静态分配,从未选择Derived::Call,这就是错误的原因。