Ежедневный бит (е) 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.