编辑:对std :: bind()的调用可以用其他东西替换,我只是想让runAsyncTerminateOnException()使用与std :: async()相同的签名,就像它只是一个包装器
我正在尝试为std :: async()创建一个包装器。 当你直接调用std :: async()时,你知道如何让包装器工作吗?
注意:我不会修改print()函数签名,这是一个例子。我希望包装器是通用的,并且可以通过直接调用std :: async()来处理所有可能的参数。
谢谢。
#include <iostream>
#include <functional>
#include <future>
template<class Fn, class... Args>
inline auto runAsyncTerminateOnException(Fn&& fn, Args&&... args) {
auto make_call = std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...);
return std::async(std::launch::async, [=]() -> decltype(make_call()) {
try {
return make_call();
} catch (...) {
std::cout << "Terminate Called!" << std::endl;
std::terminate();
}
});
}
struct Foo {
template<class... Args>
void print(Args&&... args) {
printf("Foo::print(%d)\n", std::forward<Args>(args)...);
}
};
int main() {
Foo foo;
std::future<void> future = std::async(std::launch::async, &Foo::print<int>, &foo, 2);
std::future<void> future2 = runAsyncTerminateOnException(&Foo::print<int>, &foo, 2);
// your code goes here
return 0;
}
答案 0 :(得分:2)
您需要按如下方式更改runAsyncTerminateOnException
来电:
std::future<void> future2 =
runAsyncTerminateOnException(&Foo::print<const int&>, &foo, 2);
这是由于an unfortunate interaction between std::bind
, variadic templates and perfect forwarding。
我建议您使用lambdas,它几乎总是优于std::bind
。 (有关详情,请参阅STL的this talk。)
template<class Fn>
inline auto runAsyncTerminateOnException(Fn&& fn)
{
return std::async(std::launch::async, [=]() -> decltype(fn()) {
try {
return fn();
} catch (...) {
std::cout << "Terminate Called!" << std::endl;
std::terminate();
}
});
}
(请注意,我正在将fn
复制到lambda中 - 如果您想要更正确和通用的解决方案,则应考虑perfect-forward capturing the object into the lambda。)
std::future<void> future2 =
runAsyncTerminateOnException([&foo]{ return foo.print(2); });
答案 1 :(得分:0)
我找到了c ++ 17的解决方案。 仅当我们不为runTerminateOnException()的返回类型使用auto时,它才有效。
template<class Fn, class... Args>
inline std::result_of_t<Fn&&(Args&&...)> runTerminateOnException(Fn&& fn, Args&&... args) {
try {
return std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...);
} catch (...) {
std::terminate();
}
}
template<class Fn, class... Args>
inline auto runAsyncTerminateOnException(Fn&& fn, Args&&... args) {
return std::async(std::launch::async, runTerminateOnException<Fn, Args&&...>, std::forward<Fn>(fn), std::forward<Args>(args)...);
}