成员函数作为函数模板的参数
Member function as parameter for a function template
我想注册回调函数,并将它们存储在一个向量中以供调用。还应该允许使用成员函数作为回调函数。
我最初的方法是按以下方式使用 <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 ) );
}
它奏效了。因为我不喜欢这种形式的函数指针,所以我为成员函数指针创建了一个类型:
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)'
现在回答我的问题:
是否可以为此使用 std::function
?
如果这不起作用,我可以避免指定至少两个成员函数类型吗?
在此先感谢您的帮助。
您可以通过在结构中隐藏 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 ));
}
我不得不推荐使用 lambda 而不是 std::bind
(编辑:不确定在这种情况下它是否是非推导出的上下文。可能 Foo::Bar
只能转换为 std::function<void(Foo*)>
)
Interestingly Memberfunction<Foo,void> bar = &Foo::Bar;
lead to the following error:
cannot convert from 'void (__thiscall Foo::* )(void)' to 'void (__thiscall Foo::* )(void)'
那是因为您的编译器给了您错误消息。代码本身是无效的,但它与类型Memberfunction<Foo,void>
的创建有关。只有在非依赖的特殊情况下,才可以使用 void
作为函数的参数列表。来自 [dcl.fct]:
A parameter list consisting of a single unnamed parameter of non-dependent type void
is equivalent to an empty parameter list. Except for this special case, a parameter shall not have type cv 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
是 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 ) );
}
否则它不会是无效的。或者,更一般地说:
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)...));
}
我想注册回调函数,并将它们存储在一个向量中以供调用。还应该允许使用成员函数作为回调函数。
我最初的方法是按以下方式使用 <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 ) );
}
它奏效了。因为我不喜欢这种形式的函数指针,所以我为成员函数指针创建了一个类型:
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)'
现在回答我的问题:
是否可以为此使用 std::function
?
如果这不起作用,我可以避免指定至少两个成员函数类型吗?
在此先感谢您的帮助。
您可以通过在结构中隐藏 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 ));
}
我不得不推荐使用 lambda 而不是 std::bind
(编辑:不确定在这种情况下它是否是非推导出的上下文。可能 Foo::Bar
只能转换为 std::function<void(Foo*)>
)
Interestingly
Memberfunction<Foo,void> bar = &Foo::Bar;
lead to the following error:cannot convert from 'void (__thiscall Foo::* )(void)' to 'void (__thiscall Foo::* )(void)'
那是因为您的编译器给了您错误消息。代码本身是无效的,但它与类型Memberfunction<Foo,void>
的创建有关。只有在非依赖的特殊情况下,才可以使用 void
作为函数的参数列表。来自 [dcl.fct]:
A parameter list consisting of a single unnamed parameter of non-dependent type
void
is equivalent to an empty parameter list. Except for this special case, a parameter shall not have type cvvoid
.
我可以写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)
是一个需要一个参数的函数。这行不通。你也必须传入浮点数:
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)...));
}