让我通过以下示例说明我的问题。假设我们有一个基类定义了方法 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;}
我想念什么?
答案 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
,这就是错误的原因。