gpt4 book ai didi

c++ - std::visit和std::variant用法

转载 作者:行者123 更新时间:2023-12-02 10:21:48 27 4
gpt4 key购买 nike

#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是一个简单的函数,它执行以下操作:
  • 如果变量包含std::exception_ptr的值,请重新引发异常。
  • 如果变量包含T的值(当T由用户设置时,也可能是std::exception_ptr),请将其返回。如果T的类型为空,则什么也不做。

  • 最初,我使用 .index() check和 std::get实现它。它可以工作,但是 std::get东西会在内部生成额外的检查,而 std::__1::__throw_bad_variant_access()东西不会发生: https://godbolt.org/z/YnjxDy

    我想根据 cppreference使用std::visit来优化代码,但无法对其进行编译。

    另一个问题是,当T的类型为std::exception_ptr时,我如何知道是否应该抛出它?

    最佳答案

    visit不会“优化”代码-这只是匹配variant的一个好模式,对于确保您不会忘记任何类型特别有用。

    但是visit的要求之一是,每个替代项都必须返回相同的类型。在您的用例中,这尤其成问题,因为应该只返回您的一种替代方案……所以这不是一个很好的选择。您还需要处理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_);
    }
    }
    }
    }

    我认为这比显式使用 012更好。

    Another problem is that when the type of T is std::exception_ptr, how can I know whether I should throw it?



    简单:您不扔它。根据您的类型,通用代码中的语义不会有很大不同。如果 Promise<T>::await_resume()包含 T,则返回 TPromise<std::exception_ptr>::await_resume()返回一个 exception_ptr。没关系。

    我想实际上在上面的实现中,使用显式的 get_if<exception_ptr>会变得模棱两可,这很不幸……所以 0 / 1 / 2也许只是简单的方法。

    关于c++ - std::visit和std::variant用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59853593/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com