我想注册回调函数,并将它们存储在 vector 中以调用它们。还应该允许将成员函数用作回调函数。
我最初的方法是通过以下方式使用<functional>
:
#include <functional>
#include <vector>
#include <iostream>
std::vector<std::function<void()>> functions;
struct Foo {
void Bar() {
std::cout << "Hello" << std::endl;
}
};
template<class T>
void Register( T* obj, std::function<void(T*)> function ) {
functions.push_back( std::bind( function, obj ) );
}
void main(){
Foo foo;
Register(&foo, &Foo::Bar);
}
这不起作用,因为编译器无法推断出参数类型。仅当我明确指定类型时才有效:
Register<Foo>(&foo, &Foo::Bar);
。这不是我想要的,所以我尝试使用旧的函数指针:template<class T>
void Register( T* obj, void(T::* function)() ) {
functions.push_back( std::bind( function, obj ) );
}
而且有效。由于我不喜欢这种形式的函数指针,因此我为Memberfunction指针创建了一种类型:
template<class Owner>
using Memberfunction = void( Owner::* )();
template<class T>
void Register( T* obj, Memberfunction<T> function ) {
functions.push_back( std::bind( function, obj ) );
}
这很好。但是现在我想用一个参数来支持函数,因为我不想为每种参数类型都指定一个Memberfunction,所以我想再次使用模板。
template<class Owner, class Param>
using Memberfunction = void( Owner::* )( Param );
template<class T>
void Register( T* obj, Memberfunction<T,float> function ) {
using namespace std::placeholders;
functions.push_back( std::bind( function, obj, _1 ) );
}
到目前为止,这种方法很好用,但是我不想为一个或没有参数指定成员函数,所以我想使用
void
作为Memberfunction
的第二个参数,但这会导致内部编译器错误,所以我猜这行不通。有趣的是
Memberfunction<Foo,void> bar = &Foo::Bar;
导致以下错误:cannot convert from 'void (__thiscall Foo::* )(void)' to 'void (__thiscall Foo::* )(void)'
所以现在我的问题是:
是否可以为此使用
std::function
?如果这不起作用,是否可以避免至少指定两个成员函数类型?
在此先感谢您的帮助。
最佳答案
那是因为您的编译器给您一个错误的错误消息。代码本身是无效的,但它与创建Memberfunction<Foo,void>
类型有关。仅在不依赖函数的特殊情况下,才可以将void
用作函数的参数列表。从[dcl.fct]:
我可以写void(void)
类型。但是我不能写template <class T> using F = void(T); F<void>
类型。在这种情况下,您尝试使用相关的void
类型作为参数列表来创建一个指向成员的指针函数。
您虽然不需要std::function
。只需修复您的别名声明即可不传入任何参数:
template<class Owner, class... Params>
using Memberfunction = void( Owner::* )( Params... );
Memberfunction<Foo> bar = &Foo::Bar;
也就是说,这没有多大意义:
template<class T>
void Register( T* obj, Memberfunction<T,float> function ) {
using namespace std::placeholders;
functions.push_back( std::bind( function, obj, _1 ) );
}
functions
是std::function<void()>
的容器(即,空函数对象),但是std::bind(function, obj, _1)
是需要一个参数的函数。这行不通。您也必须通过 float :template<class T>
void Register( T* obj, Memberfunction<T,float> function, float var ) {
functions.push_back( std::bind( function, obj, var ) );
}
否则它将不会是空值。或者,更一般而言:
template <class T, class MF, class... Args>
void Register(T* obj, MF mem_fun, Args&&... args) {
functions.push_back(std::bind(obj, mem_fun, std::forward<Args>(args)...));
}