【问题标题】:How to combine std::bind(), variadic templates, and perfect forwarding?如何结合 std::bind()、可变参数模板和完美转发?
【发布时间】:2013-08-25 04:56:30
【问题描述】:

我想通过第三方函数调用另一个方法;但两者都使用可变参数模板。例如:

void third_party(int n, std::function<void(int)> f)
{
  f(n);
}

struct foo
{
  template <typename... Args>
  void invoke(int n, Args&&... args)
  {
    auto bound = std::bind(&foo::invoke_impl<Args...>, this,
                           std::placeholders::_1, std::forward<Args>(args)...);

    third_party(n, bound);
  }

  template <typename... Args>
  void invoke_impl(int, Args&&...)
  {
  }
};

foo f;
f.invoke(1, 2);

问题是,我得到一个编译错误:

/usr/include/c++/4.7/functional:1206:35: error: cannot bind ‘int’ lvalue to ‘int&&’

我尝试使用 lambda,但 maybe GCC 4.8 尚未处理语法;这是我尝试过的:

auto bound = [this, &args...] (int k) { invoke_impl(k, std::foward<Args>(args)...); };

我收到以下错误:

error: expected ‘,’ before ‘...’ token
error: expected identifier before ‘...’ token
error: parameter packs not expanded with ‘...’:
note:         ‘args’

据我了解,编译器希望用int&amp;&amp; 类型实例化invoke_impl,而我认为在这种情况下使用&amp;&amp; 会保留实际参数类型。

我做错了什么?谢谢,

【问题讨论】:

  • GCC 4.8 完美地处理了语法。你尝试了什么?
  • @ArneMertz 我用我尝试过的语法更新了问题
  • 看来你刚刚在 gcc 中遇到了一个错误,它应该可以工作:gcc.gnu.org/bugzilla/show_bug.cgi?id=41934

标签: c++ templates c++11 variadic-templates perfect-forwarding


【解决方案1】:

绑定到&amp;foo::invoke_impl&lt;Args...&gt; 将创建一个绑定函数,该函数接受Args&amp;&amp; 参数,即右值。问题是传递的参数将是一个左值,因为参数被存储为某个内部类的成员函数。

要解决此问题,请通过将 &amp;foo::invoke_impl&lt;Args...&gt; 更改为 &amp;foo::invoke_impl&lt;Args&amp;...&gt; 来利用引用折叠规则,因此成员函数将采用左值。

auto bound = std::bind(&foo::invoke_impl<Args&...>, this,
                       std::placeholders::_1, std::forward<Args>(args)...);

Here is a demo.

【讨论】:

  • 实际上,如果我使用std::reference_wrapper 作为参数,这个解决方案似乎不起作用,这里是一个例子:ideone.com/VBxfZd;我是否遗漏了有关使用参考包装器的内容?
  • @piwi 然后将Args&amp;... 更改为Args const&amp;...。不完全确定它为什么会起作用。
  • 我的错,我本来可以想出这个的 ;-) 谢谢。
猜你喜欢
  • 1970-01-01
  • 2011-09-23
  • 2015-09-07
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
  • 2019-04-30
  • 1970-01-01
相关资源
最近更新 更多