使用可变参数模板的成员函数指针包装器(gcc,clang)

时间:2018-03-24 12:12:52

标签: c++ c++11 templates variadic-templates member-function-pointers

为什么以下代码无法在gcc或clang下编译:

class Foo {
public:
    void bar(int) {}
};

template< class T, typename ...Args, void(T::*Member)(Args...) >
void member_dispatch(Args&&... args, void* userdata)
{
    T* obj = static_cast<T*>(userdata);
    (obj->*Member)(std::forward<Args>(args)...);
}

int main()
{
    Foo foo;
    member_dispatch<Foo, int, &Foo::bar>(1, &foo);
    return 0;
}

参见例如here

这个问题可能与this合并了一个问题,虽然在这里我从gcc和clang(而不是VS)中得到了不明确的编译错误。

2 个答案:

答案 0 :(得分:3)

当您明确指定类型时,参数包是贪婪的。 &Foo::bar将被解析为typename ...Args的一部分,从而导致错误。

写这个的正确方法是将它放在函数参数列表中,而不是非类型模板参数。

template< class T, typename ...Args>
void member_dispatch(Args&&... args, void(T::*Member)(Args...), void* userdata)
{
    T* obj = static_cast<T*>(userdata);
    (obj->*Member)(std::forward<Args>(args)...);
}

int main()
{
    Foo foo;
    member_dispatch<Foo, int>(1, &Foo::bar, &foo);
    return 0;
}

更好的方式:

最好利用C ++的模板参数推导。但是在这里你没有将参数pact放在函数参数列表的末尾,这是一个非推断的上下文。所以我建议你重新订购它,这样你就不需要指定模板参数:

template<class T, class K, typename ...Args>
void member_dispatch(K T::*ptr, void* userdata, Args&&... args)
{
    T* obj = static_cast<T*>(userdata);
    (obj->*ptr)(std::forward<Args>(args)...);
}

int main()
{
    Foo foo;
    member_dispatch(&Foo::bar, &foo, 1);
    return 0;
}

答案 1 :(得分:0)

尝试使用类模板而不是函数模板。 还有一个std语法提议&#34; template&lt;&lt;自动x&gt;&gt; &#34;对于非类型模板参数。正确的实现将简化您的库语法。