我试图创建一种std :: thread形式,它将一个包装器放在线程中执行的代码中。不幸的是,由于我对rvalues和Function
模板化类型I的尝试很难理解,我无法编译它。这是我的代码:
#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<Function, Args...>
与给予std :: thread的rvalues f, a...
之间的不匹配。
奇怪的是,如果我将std::forward<Function>(f)
更改为std::ref(f)
,则会在GCC4.9和更新的Clang中编译。
答案 0 :(得分:5)
这是一种罕见的情况,其中传递函数和传递函数指针之间的区别有所不同。如果你这样做:
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)...);
}
};