2016-12-13 2 views
0

Я пытаюсь создать оболочку, которая вызывает std :: terminate(), когда она улавливает исключение. Я бы хотел, чтобы эта оболочка принимала те же аргументы, что и std :: async() (это может быть вызов функции, а также вызов метода). Кто-то знает, как сделать этот код компилируемым?C++ std :: async() завершает исключение перед вызовом future.get()

Спасибо

http://ideone.com/tL7mTv

#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

Он компилируется на вашем компьютере? Ошибка при компиляции, если вы переходите по ссылке на ideone.com – infiniteLoop

ответ

0

Я нашел решение для C++ 17. Он работает, только если мы не используем auto для возвращаемого типа runTerminateOnException().

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)...); 
} 
0

Я лично думаю, что вы более сложным это немного. Вы можете просто привязать вызов и использовать простую лямбду, чтобы сделать упаковку.

#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.

+0

Большое спасибо. Но у меня проблема, когда метод вызова содержит переменные параметры. Вы можете увидеть эту проблему здесь: http://ideone.com/psnQgJ. Вы знаете, почему он не работает при вызове напрямую std :: async() работает? – infiniteLoop

+0

Да, вы можете видеть, как он работает здесь с async(): http://ideone.com/2IiFvp – infiniteLoop

+0

@ user3782790 Я должен сказать, что это меня озадачивает. Мне нужно исследовать – StoryTeller

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 :: печать потребовав int&&, конечно, это. Вот что вы написали:

void print(Args&&... args) 

Непригодно для функции печати требовать владения объектами. Заявите его как следует:

struct Foo { 
    template<class... Args> 
    void print(const Args&... args) { 
     printf("Foo::print(%d)\n", args...); 
    } 
}; 
+0

Благодарим за предложение. Но, к сожалению, у меня есть ошибка, когда метод вызова содержит переменные параметры, в то время как вызывается прямо std :: async(). Вот тот же код, вызывающий вариационный метод: http://ideone.com/N20Vi4 – infiniteLoop

+0

@ user3782790 обновлено –

+0

Конечно, я не использую функцию печати. Это упрощенный пример. Мне нужно перенаправить параметры стандартным образом, так как стандартная библиотека C++ обрабатывает вариативные шаблоны. Вы можете увидеть этот шаблон во всех функциях стандартной библиотеки C++ – infiniteLoop

Смежные вопросы