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

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

本文关键字:参数 function std 派生 重载 函数 带有 C++      更新时间:2023-10-16

让我用下面的例子来说明我的问题。假设我们有一个基类,它定义了方法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)>&)'

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

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

我错过了什么?

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

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

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

即使由于完全匹配而选择了 Base 中的模板函数,在它内部,您也会将func传递给接受可转换为std::function<void(void)>的东西的Base::Call,而 lambda 不是。 由于静态调度,Derived::Call从未被选中,这就是错误的原因。