visit
не «оптимизирует» код - это просто хороший шаблон для сравнения на variant
, и особенно полезно убедиться, что вы не забыли ни о каких типах.
Но одно из требований visit
заключается в том, что каждая альтернатива должна возвращать один и тот же тип. Это особенно проблематично c в вашем случае использования, поскольку должна быть возвращена только одна из ваших альтернатив ... так что она просто не подходит. Вам также нужно для обработки monostate
дела в visit
, и у вас действительно нет никакого способа сделать это (кроме ... броска?), Так что вам просто не повезло.
Версия, с которой вы работали раньше, прекрасно, я бы просто пометил ее типами, чтобы она была более выразительной:
struct Void { };
template <typename T>
struct Promise {
using Value = std::conditional_t<std::is_void_v<T>, Void, T>;
std::variant<
std::monostate,
Value,
std::exception_ptr
> result_;
T await_resume() const {
assert(not result_.valueless_by_exception());
assert(not std::holds_alternative<std::monostate>(result_));
if (auto* exc = std::get_if<std::exception_ptr>(&result)) {
std::rethrow_exception(*exc);
} else {
if constexpr (not std::is_void_v<T>) {
return std::get<T>(result_);
}
}
}
}
Я думаю, что это немного лучше, чем использование 0
, 1
и 2
явно.
Другая проблема состоит в том, что когда тип T
равен std::exception_ptr
, как я могу узнать, должен ли я его бросить?
Простой: Вы не бросаете его. Не используйте сильно различную семантику в обобщенном c коде, основанном на вашем типе. Promise<T>::await_resume()
возвращает T
, если оно содержит T
. Promise<std::exception_ptr>::await_resume()
возвращает exception_ptr
. Хорошо.
Полагаю, на самом деле с моей реализацией, приведенной выше, использование явного get_if<exception_ptr>
станет двусмысленным, что вызывает сожаление ... поэтому, возможно, 0
/ 1
/ 2
- это просто простой способ go.