#include <variant>
#include <exception>
#include <type_traits>
#include <cassert>
template <typename T>
struct Promise {
std::variant<
std::monostate,
std::conditional_t<std::is_void_v<T>, std::monostate, T>,
std::exception_ptr
> result_;
T await_resume() const {
assert(result_.index() > 0);
#if 1
// old code that I want to optimise
if (result_.index() == 2) {
std::rethrow_exception(std::get<2>(result_));
}
if constexpr (!std::is_void_v<T>) {
return std::get<1>(result_);
}
#else
// new code, won't compile
return std::visit([](auto&& arg) {
using TT = std::decay_t<decltype(arg)>;
if constexpr (!std::is_same_v<TT, std::exception_ptr>) {
std::rethrow_exception(arg);
} else if constexpr (!std::is_void_v<T>) {
return arg;
}
});
#endif
}
};
template int Promise<int>::await_resume() const;
template std::exception_ptr Promise<std::exception_ptr>::await_resume() const;
template void Promise<void>::await_resume() const;
Promise::await_resume is a simple function which does following thing:
- If the variant holds a value of
std::exception_ptr
, rethrow the exception. - If the variant holds a value of
T
(while T is set by users, may also be std::exception_ptr), return it out. If type of T is void, do nothing.
Originally I implement it using .index()
check and std::get
. It works, but std::get
things generate extra checks internally and std::__1::__throw_bad_variant_access()
things that not expected to happen: https://godbolt.org/z/YnjxDy
I want to optimise the code using std::visit according to cppreference, but can't get it compile.
Another problem is that when the type of T is std::exception_ptr, how can I know whether I should throw it?