具有单个参数模板的成员函数包装器?

时间:2015-12-16 23:27:24

标签: c++ templates member-pointers

我创建了一个模板函数,它将一个成员函数作为参数。

但是,由于必须先声明该类才能将其用作成员函数参数的一部分,因此我必须将其作为单独的参数:

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声明为&#34;自由变量&#34;然后有一个内部模板参数执行演绎

template<typename C>
template<void (C::*Method)(void)>
function<void(C*)> methodWrap()
{
}

2 个答案:

答案 0 :(得分:2)

如果您可以使用成员函数指针的正常函数参数而不是使其成为模板参数,则可以执行

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

答案 1 :(得分:0)

  

为什么我不能写这样的东西:

template<void (C::*Method)(void)>
function<void(C*)> methodWrap()

因为这里无法确定C的类型。因此需要typename C

  

或者为什么我不能将它包装在一个声明C为a的外部模板中   “自由变量”然后有一个执行的内部模板参数   扣除

我不确定这会如何帮助你摆脱困境。您仍然需要一种在模板参数列表中指定对象类型的方法。

你可以这样做:

 template<typename C>
 std::function<void(C&)> wrap(void(C::*mf)())
 {
   return std::function<void(C&)>(mf);
 }

用法:wrap(&Obj::memfun);

当然,要通过指针实际调用非静态成员函数,您将需要一个实例对象。