我想注册回调函数,并将它们存储在 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 ) );
}
functionsstd::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)...));
}

10-08 09:25
查看更多