【问题标题】:Perfect Forwarding Variadic Template to Standard Thread将可变参数模板完美转发到标准线程
【发布时间】:2014-11-19 23:29:24
【问题描述】:

我正在尝试制作一种 std::thread 形式,它在线程中执行的代码周围放置一个包装器。不幸的是,由于我对右值和我试图传递的 Function 模板类型的理解很差,我无法编译它。这是我的代码:

#include <vector>
#include <thread>
#include <utility>

void Simple2(int a, int b) {}

template <typename Function, typename... Args>
void Wrapper(Function&& f, Args&&... a) {
  f(std::forward<Args>(a)...);
}

class Pool {
 public:
  template <typename Function, typename... Args>
  void Binder(Function&& f, Args&&... a) {
    std::thread t(Wrapper<Function, Args...>,
                  std::forward<Function>(f), std::forward<Args>(a)...);
  }
};

int main() {
  Wrapper(Simple2, 3, 4);       // Works

  Pool pool;
  pool.Binder(Simple2, 3, 4);   // Doesn't compile
}

这里看起来很重要的 Clang3.0 输出是:

/usr/include/c++/4.6/functional:1286:9: error: non-const lvalue reference to type 'void (int, int)' cannot bind to a value of unrelated type 'void (*)(int, int)'

note: in instantiation of function template specialization 'std::thread::thread<void (void (&)(int, int), int &&, int &&), void (&)(int, int), int, int>' requested here

我认为这暗示了 Wrapper&lt;Function, Args...&gt; 和给予 std::thread 的右值 f, a... 之间的不匹配。

如果我将 std::forward&lt;Function&gt;(f) 更改为 std::ref(f),这会在 GCC4.9 和更新的 Clang 中编译。

【问题讨论】:

    标签: c++ c++11 rvalue-reference stdthread perfect-forwarding


    【解决方案1】:

    这是传递函数和传递函数指针之间的区别的少数情况之一。如果你这样做:

    pool.Binder(&Simple2, 3, 4);  
    

    它应该工作。或者,您可以让Binder 将其参数衰减为函数指针:

    class Pool {
     public:
      template <typename Function, typename... Args>
      void Binder(Function&& f, Args&&... a) {
        std::thread t(Wrapper<typename std::decay<Function>::type, Args...>,
                      std::forward<Function>(f), std::forward<Args>(a)...);
      }
    };
    

    在 C++14 中简化为:

    class Pool {
     public:
      template <typename Function, typename... Args>
      void Binder(Function&& f, Args&&... a) {
        std::thread t(Wrapper<std::decay_t<Function>, Args...>,
                      std::forward<Function>(f), std::forward<Args>(a)...);
      }
    };
    

    【讨论】:

    • 这修复了 g++4.7+ 的问题。不幸的是,invalid initialization of reference of type 'void (*&amp;&amp;)(int, int)' from expression of type 'void (*)(int, int)' 的 gcc4.6 中仍然存在错误。现在可能这是 gcc4.6 附带的 stdlib 的问题。
    • 你是一个救生员。一整天都在这个问题上迷失了,我终于找到了解决方案。你能详细说明为什么传递函数指针会有所不同吗?千谢谢。
    • @PauloNeves:很高兴我能帮上忙。绑定到参考参数时,没有“衰减”。当绑定到按值参数时,某些类型会衰减:函数参数衰减为指向函数的指针;数组参数衰减为指向数组元素类型的指针;顶级 cv 限定符在衰减中被丢弃。函数类型很有趣(以一种糟糕的方式),您不想处理它们。所以通常最好将函数类型衰减为函数指针类型。我忘记了为什么函数类型难以处理的所有细节。我只是感到震惊并学会了不要触摸热线。
    猜你喜欢
    • 2011-09-23
    • 1970-01-01
    • 2013-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-06
    • 2016-03-22
    • 1970-01-01
    相关资源
    最近更新 更多