首先让我们看一下具体的功能:
void boo1 () { std::cout << "boo1\n"; }
void boo2 (std::string) { std::cout << "boo2\n"; }
struct X {
void boo3 () { std::cout << "boo3\n"; }
void boo4 (std::string) { std::cout << "boo4\n"; }
};
我希望这些函数在执行时受到"保护"函数的保护,以进行异常保护(下面有解释)。因此,我编写了两个函数,一个用于自由函数,另一个用于成员函数:
template <typename C, typename... Args>
typename std::enable_if<!std::is_member_function_pointer<C>::value, void>::type
foo (C&& c, Args&&... args) {
std::cout << "not memfun\n";
c (std::forward<Args> (args)...);
}
template <typename C, typename T, typename... Args>
typename std::enable_if<std::is_member_function_pointer<C>::value, void>::type
foo (C&& c, T* o, Args&&... args) {
std::cout << "memfun\n";
(o->*c) (std::forward<Args> (args)...);
}
现在我想要在新线程中执行boo1()
、boo2()
、X::boo3()
和X::boo4()
,但要使用foo()
函数所使用的“保护”机制。因此,我可以轻松地使用以下方法:
X x;
std::thread th1 {&foo<void (*) ()>, &boo1};
std::thread th2 {&foo<void (*) (std::string), std::string>, &boo2, "Hello"};
std::thread th3 {&foo<void (X::*) (), X>, &X::boo3, &x};
std::thread th4 {&foo<void (X::*) (std::string), X, std::string>, &X::boo4, &x, "Hello"};
因此,更进一步地说,我编写了线程包装类,以避免显式使用
std::join()
或std::detach()
。当析构函数被调用时,其中一个函数将被调用。为了简化这个示例,我只使用了其中一个函数。因此,代码如下:class Th {
public:
template <typename C,
typename = typename std::enable_if<!std::is_member_function_pointer<C>::value, void>::type,
typename... Args>
Th (C&& c, Args... args) // (X)
: t {foo<C, Args...>, std::forward<C> (c), std::forward<Args> (args)...} {}
template <typename C,
typename = typename std::enable_if<std::is_member_function_pointer<C>::value, void>::type,
typename T,
typename... Args>
Th (C&& c, T* o, Args... args) // (Y)
: t { foo<C, T, Args...>, std::forward<C> (c), o, std::forward<Args> (args)...} {}
~Th () { t.join (); }
private:
std::thread t;
};
通过这种实现方式,以下使用情况没有问题:
X x;
Th h1 {&boo1};
Th h2 {&boo2, "Hello"};
Th h3 {&X::boo3, &x};
Th h4 {&X::boo4, &x, "Hello"};
工作正常。但是这里有一个缺陷 - 没有完美的转发。如果我在(X)
和(Y)
中改变Args...
为Args&&...
,这是期望的,
代码无法编译并出现一些错误之一:
error: no type named ‘type’ in ‘class std::result_of<void (*(void (*)(std::basic_string<char>), const char*))(void (*&&)(std::basic_string<char>), const char (&)[6])>’
如果我理解正确,
std::thread
构造函数中的std::bind()
不能发挥其作用,请纠正我如果我错了。我的问题是:在这种情况下我该怎么做才能利用完美转发? 编译时使用的编译器是GCC 4.8.1。 承诺的解释:我想让
foo()
函数用try
和catch
包围对c()
的调用,以确保异常被捕获,在某种日志机制中处理此信息,如果需要透明地向Th
类的用户重新抛出异常。
h2
和h4
中使用std::string("Hello")
而不是普通的"Hello"
运行它,它将无法编译。错误是no known conversion from 'std::__cxx11::basic_string<char>' to 'std::__cxx11::basic_string<char> &&' for 1st argument auto forward_to_thread(T&& t)
(clang 5.0
). - cantordustforward_to_thread
的参数也应该被转发,问题已经修复。谢谢。 - krzaq