如何将重载的成员函数作为参数传递?
How to pass an overloaded member-function as parameter?
这是我面临的问题:我在 class 中有一个重载函数,我想将其重载之一作为参数传递。但是这样做时,出现以下错误:
"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 );
您需要转换为 member-function 指针,而不是 std::function
:
otherFunction ( static_cast<void(Bar::*)(const Foo&)>(&Bar::function) );
[编辑]
解释:
otherFunction ( &Bar::function );
otherFunction
以 std::function
作为参数。 std::function
有一个来自函数指针(成员函数或自由函数,以及其他 "callable" 类型,在这里无关紧要)的隐式构造函数(隐式转换)。它看起来像这样:
template< class F >
function( F f );
- 这是一个模板参数
- 而
F
是"callable",它没有指定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;
}
(See Online)
为了避免一些麻烦,您可能需要使用宏。
#define OVERLOADED(f) \
[&](auto&&...xs)noexcept->decltype(auto)\
{return std::invoke(f, decltype(xs)(xs)...);}
int main(){
g(OVERLOADED(&Bar::function));
}
这是我面临的问题:我在 class 中有一个重载函数,我想将其重载之一作为参数传递。但是这样做时,出现以下错误:
"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 );
您需要转换为 member-function 指针,而不是 std::function
:
otherFunction ( static_cast<void(Bar::*)(const Foo&)>(&Bar::function) );
[编辑]
解释:
otherFunction ( &Bar::function );
otherFunction
以 std::function
作为参数。 std::function
有一个来自函数指针(成员函数或自由函数,以及其他 "callable" 类型,在这里无关紧要)的隐式构造函数(隐式转换)。它看起来像这样:
template< class F >
function( F f );
- 这是一个模板参数
- 而
F
是"callable",它没有指定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;
}
(See Online)
为了避免一些麻烦,您可能需要使用宏。
#define OVERLOADED(f) \
[&](auto&&...xs)noexcept->decltype(auto)\
{return std::invoke(f, decltype(xs)(xs)...);}
int main(){
g(OVERLOADED(&Bar::function));
}