Ежедневный бит (е) C++ # 106, Использование поддержки хранения и повторного создания исключений C++ 11 при реализации сопрограмм.
При реализации сопрограмм мы должны решить, как мы хотим обрабатывать исключения.
Одним из вариантов является игнорирование исключений и завершение метода unhandled_exception()
.
В качестве альтернативы мы можем использовать поддержку хранения и повторного создания исключений C++11:
std::current_exception
std::exception_ptr
std::rethrow_exception
#include <iostream> #include <coroutine> #include <exception> template <typename Result> struct Promise; // Result type template <typename Result> struct Task : std::coroutine_handle<Promise<Result>> { using promise_type = Promise<Result>; ~Task() { this->destroy(); } Result& get_value() { // if the coroutine ended with exception, rethrow if (this->promise().exception_) std::rethrow_exception(this->promise().exception_); // otherwise, return the result return this->promise().value_; } }; // Promise type template <typename Result> struct Promise { Task<Result> get_return_object() { return {Task<Result>::from_promise(*this)}; } std::suspend_always initial_suspend() noexcept { return {}; } std::suspend_always final_suspend() noexcept { return {}; } void return_value(auto&& val) { // store the result value_ = std::forward<decltype(val)>(val); } void unhandled_exception() { // store the exception exception_ = std::current_exception(); } Result value_; std::exception_ptr exception_; }; Task<int> coro_success() { co_return 1; } Task<int> coro_throws() { throw std::runtime_error("Failed."); co_return 2; } try { auto c1 = coro_success(); c1.resume(); // let the coroutine run std::cout << c1.get_value() << "\n"; // prints "1" auto c2 = coro_throws(); c2.resume(); // let the coroutine run std::cout << c2.get_value() << "\n"; // c2.get_value() rethrows the exception } catch (const std::exception& e) { // e.what() == "Failed." std::cout << e.what() << "\n"; }
Откройте пример в Compiler Explorer.