如何将重载成员函数作为参数传递?



这是我面临的问题:我在类中有一个重载函数,我想将其重载之一作为参数传递。但是这样做时,我收到以下错误:

"no suitable constructor exists to convert from <unknown-type> to std::function<...>"

下面是一个代码示例来说明这一点:

#include <functional>
#include <string>
class  Foo
{
private:
int val1 , val2;
};    
class Bar
{
public:
void function ( ) {
//do stuff;
Foo f;
function ( f );
}    
void function ( const Foo& f ) {
//do stuff
}
private:
//random attribute
std::string str;    
};

void otherFunction ( std::function<void ( Bar& , const  Foo& ) > function ) {
Bar b;
Foo f;
function(b,f);
}
int main ( ) {    
otherFunction ( &Bar::function );
^^^
error
}

我知道编译器无法推断出要使用哪个重载,所以下一个最好的办法是static_cast,但以下代码仍然有相同的错误

std::function<void ( Bar& , const Foo& )> f = static_cast< std::function<void ( Bar& , const Foo& )> > ( &Bar::function );

你需要强制转换为成员函数指针,而不是std::function

otherFunction ( static_cast<void(Bar::*)(const Foo&)>(&Bar::function) );

[编辑]

解释:

otherFunction ( &Bar::function );

otherFunctionstd::function作为参数。std::function有一个来自函数指针的隐式构造函数(隐式转换)(成员函数或自由函数,以及其他"可调用"类型,在这里无关紧要)。它看起来像这样:

template< class F > 
function( F f );
  • 这是一个模板参数
  • 虽然F是"可调用的",但它没有指定F的签名

这意味着编译器不知道你的意思是哪个Bar::function,因为这个构造函数不会对输入参数施加任何限制。这就是编译器所抱怨的。

你试过了

static_cast< std::function<void ( Bar& , const Foo& )> > ( &Bar::function );

虽然看起来编译器在这里有它需要的所有细节(签名),但实际上调用了相同的构造函数,所以没有有效地改变。 (实际上,签名不正确,但即使是正确的签名也不起作用)

通过强制转换为函数指针,我们提供其签名

static_cast<void(Bar::*)(const Foo&)>(&Bar::function)

因此,歧义得到解决,因为只有一个这样的函数,因此编译器很高兴。

如果使用类型化成员函数指针和模板化otherFunction,则代码将起作用。这意味着,将您的otherFunction()更改为:

template<typename Class, typename T>
void otherFunction(void(Class::*)(T) ) {
Bar b;
Foo f;
b.function(f);
}

如果语法令人困惑,请对成员函数指针使用帮助程序(模板)别名:

template<typename Class, typename T>
using MemFunPtr = void(Class::*)(T);
template<typename Class, typename T>
void otherFunction(MemFunPtr<Class, T> function) {
Bar b;
Foo f;
b.function(f);
}

现在,您可以在不进行类型转换的情况下调用该函数。

int main()
{
otherFunction(&Bar::function);
return 0;
}

(见在线)

您可能需要使用宏以避免一些头痛。

#define OVERLOADED(f) 
[&](auto&&...xs)noexcept->decltype(auto)
{return std::invoke(f, decltype(xs)(xs)...);}
int main(){
g(OVERLOADED(&Bar::function));
}

相关内容

  • 没有找到相关文章

最新更新