我正在尝试创建一个在捕获异常时调用std :: terminate()的包装器。 我希望这个包装器采用与std :: async()相同的参数(它可以是对函数的调用以及对方法的调用)。 有人知道如何编译这段代码吗?
谢谢
#include <iostream>
#include <functional>
#include <future>
template<class Fn, class... Args>
inline auto runTerminateOnException(Fn&& fn, Args&&... args) {
try {
return std::bind(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)...);
}
struct Foo {
void print() {
printf("Foo::print()\n");
}
};
int main() {
Foo foo;
std::future<void> future = runAsyncTerminateOnException(&Foo::print, &foo);
// your code goes here
return 0;
}
答案 0 :(得分:0)
我个人认为你复杂了一点。你可以绑定调用并使用一个简单的lambda进行包装。
#include <iostream>
#include <future>
#include <functional>
#include <type_traits>
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 {
void print() {
printf("Foo::print()\n");
}
void print2() {
printf("Foo::print2()\n");
throw 1;
}
};
int main() {
Foo foo;
std::future<void> future = runAsyncTerminateOnException(&Foo::print, &foo);
std::future<void> future2 = runAsyncTerminateOnException(&Foo::print2, &foo);
return 0;
}
See it live, with possible output
我显然复制了第一个闭包,而不是预先形成所需的步骤以将其移动到第二个闭包中(就像在c ++ 11中那样)。您当然可以使用c ++ 14中的特定移动捕获来移动它。
答案 1 :(得分:0)
在c ++ 17中,干净的方法是使用std::invoke
。
我已经在这里进行了黑客攻击以示证。
#include <iostream>
#include <future>
#include <functional>
#include <type_traits>
namespace std
{
template<class T>
static constexpr bool is_member_pointer_v = std::is_member_pointer<T>::value;
template<class T>
static constexpr bool is_function_v = std::is_function<T>::value;
template<class B, class T>
static constexpr bool is_base_of_v = std::is_base_of<B, T>::value;
namespace detail {
template <class T>
struct is_reference_wrapper : std::false_type {};
template <class U>
struct is_reference_wrapper<std::reference_wrapper<U>> : std::true_type {};
template <class T>
constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value;
template <class Base, class T, class Derived, class... Args>
auto INVOKE(T Base::*pmf, Derived&& ref, Args&&... args)
noexcept(noexcept((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...)))
-> std::enable_if_t<std::is_function_v<T> &&
std::is_base_of_v<Base, std::decay_t<Derived>>,
decltype((std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...))>
{
return (std::forward<Derived>(ref).*pmf)(std::forward<Args>(args)...);
}
template <class Base, class T, class RefWrap, class... Args>
auto INVOKE(T Base::*pmf, RefWrap&& ref, Args&&... args)
noexcept(noexcept((ref.get().*pmf)(std::forward<Args>(args)...)))
-> std::enable_if_t<std::is_function_v<T> &&
is_reference_wrapper_v<std::decay_t<RefWrap>>,
decltype((ref.get().*pmf)(std::forward<Args>(args)...))>
{
return (ref.get().*pmf)(std::forward<Args>(args)...);
}
template <class Base, class T, class Pointer, class... Args>
auto INVOKE(T Base::*pmf, Pointer&& ptr, Args&&... args)
noexcept(noexcept(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...)))
-> std::enable_if_t<std::is_function_v<T> &&
!is_reference_wrapper_v<std::decay_t<Pointer>> &&
!std::is_base_of_v<Base, std::decay_t<Pointer>>,
decltype(((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...))>
{
return ((*std::forward<Pointer>(ptr)).*pmf)(std::forward<Args>(args)...);
}
template <class Base, class T, class Derived>
auto INVOKE(T Base::*pmd, Derived&& ref)
noexcept(noexcept(std::forward<Derived>(ref).*pmd))
-> std::enable_if_t<!std::is_function_v<T> &&
std::is_base_of_v<Base, std::decay_t<Derived>>,
decltype(std::forward<Derived>(ref).*pmd)>
{
return std::forward<Derived>(ref).*pmd;
}
template <class Base, class T, class RefWrap>
auto INVOKE(T Base::*pmd, RefWrap&& ref)
noexcept(noexcept(ref.get().*pmd))
-> std::enable_if_t<!std::is_function_v<T> &&
is_reference_wrapper_v<std::decay_t<RefWrap>>,
decltype(ref.get().*pmd)>
{
return ref.get().*pmd;
}
template <class Base, class T, class Pointer>
auto INVOKE(T Base::*pmd, Pointer&& ptr)
noexcept(noexcept((*std::forward<Pointer>(ptr)).*pmd))
-> std::enable_if_t<!std::is_function_v<T> &&
!is_reference_wrapper_v<std::decay_t<Pointer>> &&
!std::is_base_of_v<Base, std::decay_t<Pointer>>,
decltype((*std::forward<Pointer>(ptr)).*pmd)>
{
return (*std::forward<Pointer>(ptr)).*pmd;
}
template <class F, class... Args>
auto INVOKE(F&& f, Args&&... args)
noexcept(noexcept(std::forward<F>(f)(std::forward<Args>(args)...)))
-> std::enable_if_t<!std::is_member_pointer_v<std::decay_t<F>>,
decltype(std::forward<F>(f)(std::forward<Args>(args)...))>
{
return std::forward<F>(f)(std::forward<Args>(args)...);
}
} // namespace detail
template< class F, class... ArgTypes >
auto invoke(F&& f, ArgTypes&&... args)
// exception specification for QoI
noexcept(noexcept(detail::INVOKE(std::forward<F>(f), std::forward<ArgTypes>(args)...)))
-> decltype(detail::INVOKE(std::forward<F>(f), std::forward<ArgTypes>(args)...))
{
return detail::INVOKE(std::forward<F>(f), std::forward<ArgTypes>(args)...);
}
}
template<class Fn, class... Args>
inline auto runAsyncTerminateOnException(Fn&& fn, Args&&... args) {
return std::async(std::launch::async, [=]() -> decltype(auto) {
try {
return std::invoke(fn, args...);
} catch (...) {
std::cout << "Terminate Called!" << std::endl;
std::terminate();
}
});
}
struct Foo {
void print() {
printf("Foo::print()\n");
}
void print2() {
printf("Foo::print2()\n");
throw 1;
}
};
int main() {
Foo foo;
std::future<void> future = runAsyncTerminateOnException(&Foo::print, &foo);
std::future<void> future2 = runAsyncTerminateOnException(&Foo::print2, &foo);
return 0;
}
调用模板化成员函数时出现错误:
错误是<source>: In instantiation of 'runAsyncTerminateOnException(Fn&&, Args&& ...)::<lambda()> [with Fn = void (Foo::*)(int&&); Args = {Foo*, int}]':
暗示Foo :: print当然要求int&&
。这就是你写的:
void print(Args&&... args)
打印功能要求对象的所有权是不合理的。声明它应该是:
struct Foo {
template<class... Args>
void print(const Args&... args) {
printf("Foo::print(%d)\n", args...);
}
};
答案 2 :(得分: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)...);
}