【问题标题】:Member function pointer wrapper using variadic template (gcc, clang)使用可变参数模板(gcc、clang)的成员函数指针包装器
【发布时间】:2018-03-24 12:12:52
【问题描述】:

为什么以下代码在 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)得到不清楚的编译错误。

【问题讨论】:

  • 为什么不能简单地用标准的std::functionstd::bind(或lambdas)解决你的问题?或者像几乎所有需要可调用对象的标准库函数和类一样,通过对函数类型使用单个 typename 模板参数?
  • 这是为了与使用void callback(&lt;some params&gt;, void* userdata)形式的回调的C库交互

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


【解决方案1】:

当您明确指定类型时,参数包是贪婪的。 &amp;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++ 的模板参数推导。但是这里你没有把参数约定放在函数参数列表的末尾,这是一个非推导的上下文。所以我建议你重新排序,这样就不需要指定模板参数了:

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

【讨论】:

  • 不用等待。空参数包。您需要int。我认为最好建议一个更好的 OP 替代方案。在排序类型和参数方面。
  • @StoryTeller 我错过了一些东西。我最后的评论是错误的。但仍然是非推断上下文,因为 pact 不是函数参数列表中的最后一个
  • 是的,这也是我的评论的目的。最终,最好重新安排事情以允许尽可能多的扣除。充分利用 C++ 的全部功能和所有这些细节。
  • 对于我的用例我不能将成员函数作为参数传递,它需要以某种方式编译为非类型模板参数
  • 无论如何,我想答案本身似乎是正确的,谢谢。根据 cppreference “在函数模板中,模板参数包可能出现在列表中的前面,前提是可以从函数参数中推断出所有后续参数”,我错过了那个条件
【解决方案2】:

尝试使用类模板而不是函数模板。 对于非类型模板参数,还有一个标准语法建议“template >”。正确的实现会简化你的库语法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-20
    • 2019-12-20
    相关资源
    最近更新 更多