我创建了一个模板函数,它将一个成员函数作为参数.
但是,由于必须先声明该类才能将其用作成员函数参数的一部分,因此我必须将其作为单独的参数:
template<typename C, void (C::*Method)(void)>
function<void(C*)> methodWrap()
{
}
这意味着当显式实例化模板时(我希望这些包装器在编译时生成,而不是将成员指针作为参数传递)我在使用它时必须输入两次:
function<void(C*)> someFunc = wrapMethod<SomeClass, &SomeClass::someMethod>();
为什么我不能写像tis这样的东西:
template<void (C::*Method)(void)>
function<void(C*)> methodWrap()
{
}
并让它捕获C的类型及其成员函数指针,而不必两次输入SomeClass?
或者为什么我不能将它包装在一个外部模板中,该模板将C声明为“自由变量”,然后有一个内部模板参数执行推导
template<typename C>
template<void (C::*Method)(void)>
function<void(C*)> methodWrap()
{
}
最佳答案 如果您可以使用成员函数指针的正常函数参数而不是使其成为模板参数,那么您可以这样做
#include <functional>
template<typename R, typename C, typename... Args>
struct MemberFunctionPointer
{
typedef R Return;
typedef C Class;
};
template<typename R, typename C>
constexpr auto inferMemberFunctionPointer(R (C::*method)())
{
return MemberFunctionPointer<R,C>{};
}
template<typename T>
constexpr auto methodWrap(T m)
{
typedef typename decltype(inferMemberFunctionPointer(m))::Class Class;
typedef typename decltype(inferMemberFunctionPointer(m))::Return Return;
return std::function<Return (Class*)>();
}
struct B {};
struct A
{
B f();
};
void foo()
{
auto const m = methodWrap( &A::f );
}
std :: function不是constexpr类型,因此我们不能使用methodWrap来初始化constexpr变量.您可以通过创建自己的简单constexpr成员函数包装器来绕过这一点.我还添加了一个static_assert来获得更好的错误消息.
#include <functional>
template<typename R, typename C, typename... Args>
struct MemberFunctionPointer
{
typedef R Return;
typedef C Class;
};
template<typename R, typename C>
constexpr auto inferMemberFunctionPointer(R (C::*method)() const)
{
return MemberFunctionPointer<R,C>{};
}
template<typename R, typename C>
struct MemberFunction
{
constexpr explicit MemberFunction(R (C::*g)() const): f(g) {}
constexpr R operator()(C const* obj) const
{
return (obj->*f)();
}
R (C::*f)() const;
};
template<typename T>
constexpr auto methodWrap(T m)
{
static_assert( std::is_member_function_pointer<T>::value,
"Member function pointer expected!");
typedef typename decltype(inferMemberFunctionPointer(m))::Class Class;
typedef typename decltype(inferMemberFunctionPointer(m))::Return Return;
return MemberFunction<Return, Class>{ MemberFunctionPointer<Return,Class>{} };
}
struct B {};
struct A
{
constexpr B f() const;
};
void foo()
{
auto constexpr m = methodWrap( &A::f );
auto constexpr a = A{};
m( &a );
auto b = A{};
m( &b );
}