成员函数作为函数模板的参数

时间:2016-03-10 15:29:25

标签: c++ function templates callback member

我想注册回调函数,并将它们存储在向量中以调用它们。还应该允许使用成员函数作为回调函数。

我最初的方法是以下列方式使用strBefore

<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);

它有效。由于我不喜欢这种形式的函数指针,我为Memberfunction指针创建了一个类型:

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 ) );
}

到目前为止这项工作还不错,但我不想为一个参数或没有参数指定成员函数,所以我想使用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)' 吗?

如果这不起作用,我可以避免必须指定至少两个成员函数类型吗?

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:2)

您可以通过在结构中隐藏function<void(T*)的类型来完成此工作。这避免了非推断上下文的问题:

template<typename T>
struct void_fn_type
{
    using type = std::function<void(T)>;
};

template<class T>
void Register(T* obj, typename void_fn_type<T*>::type function) {
    functions.push_back( std::bind( function, obj ));
}

Demo

我觉得不得不建议使用lambda而不是std::bind

修改:不确定它是否是此方案中未推断的上下文。可能是Foo::Bar只能转换为std::function<void(Foo*)>这一事实的问题)

答案 1 :(得分:1)

  

有趣的是innerHTML会导致以下错误:

Memberfunction<Foo,void> bar = &Foo::Bar;

那是因为你的编译器给你一个错误的错误信息。代码本身无效,但它与类型cannot convert from 'void (__thiscall Foo::* )(void)' to 'void (__thiscall Foo::* )(void)' 的创建有关。您可以将Memberfunction<Foo,void>用作函数的参数列表,仅用于它不依赖的特殊情况。来自[dcl.fct]

  

由非依赖类型void的单个未命名参数组成的参数列表等效于空参数列表。除了这种特殊情况,参数不应具有 cv void类型。

我可以写出void类型。但我不能写类型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的容器 - 即,nullary函数对象 - 但std::function<void()>是一个需要一个参数的函数。这不会奏效。你也必须通过浮动:

std::bind(function, obj, _1)

否则它不会是无效的。或者,更一般地说:

template<class T>
void Register( T* obj, Memberfunction<T,float> function, float var ) {
    functions.push_back( std::bind( function, obj, var ) );
}