完美转发可变模板到标准线程

zmo*_*tto 5 c++ rvalue-reference perfect-forwarding c++11 stdthread

我正在尝试创建一个std :: thread的形式,它将一个包装器放在线程中执行的代码中.不幸的是,由于我对rvalues和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
}
Run Code Online (Sandbox Code Playgroud)

这里看起来很重要的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)'
Run Code Online (Sandbox Code Playgroud)

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

我认为这暗示了给予std :: thread Wrapper<Function, Args...>的rvalues 之间的不匹配f, a....

奇怪的是,如果我将其更改为std::forward<Function>(f),则会在GCC4.9和更新的Clang中编译std::ref(f).

How*_*ant 6

这是传递函数和传递函数指针之间差异的罕见情况之一.如果你这样做:

pool.Binder(&Simple2, 3, 4);  
Run Code Online (Sandbox Code Playgroud)

它应该工作.或者你可以将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)...);
  }
};
Run Code Online (Sandbox Code Playgroud)

在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)...);
  }
};
Run Code Online (Sandbox Code Playgroud)