【问题标题】:Convert `std::any` to `std::variant`将 `std::any` 转换为 `std::variant`
【发布时间】:2020-04-13 07:02:20
【问题描述】:

在知道或怀疑其包含的类型之前,对于 std::any(存储它除外)没有什么可做的。然后可以查询(type())或强制转换(any_cast)。但是,当需要处理多种类型而不是一种类型时呢?在这种情况下,可以将其转换为std::variant

例如API 提供std::any 对象,但只需要有限的类型集,并且对象需要存储在容器中(向量、树等)。

std::any如何转换为std::variant


免责声明:std::any 主要用于库代码,其目的是在一些巧妙的模板和类型擦除中替换 void *。与任何新事物一样,std::any 可能会被过度使用和误用。如果std::any 是您代码的正确解决方案,请三思。

【问题讨论】:

    标签: c++ c++17 variant


    【解决方案1】:

    此代码采用std::any 对象和类型列表并将对象转换为std::variant,如果存储的类型不是给定类型之一,则抛出std::bad_any_cast

    #include <any>
    #include <variant>
    #include <optional>
    #include <typeinfo>
    
    template <class... Args>
    auto any_to_variant_cast(std::any a) -> std::variant<Args...>
    {
        if (!a.has_value())
            throw std::bad_any_cast();
    
        std::optional<std::variant<Args...>> v = std::nullopt;
    
        bool found = ((a.type() == typeid(Args) && (v = std::any_cast<Args>(std::move(a)), true)) || ...);
    
        if (!found)
            throw std::bad_any_cast{};
    
        return std::move(*v);
    }
    

    示例用法:

    auto test(const std::any& a)
    {
        auto v = any_to_variant_cast<int, std::string>(a);
    
        std::visit([](auto val) { std::cout << val << std::endl; }, v);
    }
    

    Code on godbolt


    一些解释:

    之所以使用std::optional&lt;std::variant&lt;Args...&gt;&gt;,是因为std::variant&lt;Args...&gt; default constructor 构造了保存第一个备选方案的值初始化值的变量,并且要求第一个备选方案是默认可构造的。

       ((a.type() == typeid(Args) && (v = std::any_cast<Args>(std::move(a)), true)) || ...)
    //   ------------------------     -------------------------------------  
    //          type_check                             any_cast            
    

    这是fold expression。我已经重命名了一些子表达式以便于解释。随着重命名,表达式变为:

    // ((type_check && (any_cast, true)) || ...)
    
    • 如果type_checkfalse 那么:
      • 由于&amp;&amp; 短路,(any_cast, true) 未评估
      • (type_check &amp;&amp; (any_cast, true)) 评估为 false
      • 计算折叠表达式中的下一个操作
    • 如果type_checktrue 那么:
      • (any_cast, true) 被评估:
        • any_cast 被评估。变体从任何对象中获取值。
        • any_cast 结果被丢弃
        • true 被评估
        • (any_cast, true) 评估为 true
      • (type_check &amp;&amp; (any_cast, true)) 评估为 true
      • 由于|| 的短路,未评估其余折叠
      • 整个表达式(折叠)计算为true
    • 如果没有type_check 计算为true,则整个表达式(折叠)计算为false

    【讨论】:

      猜你喜欢
      • 2019-10-11
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      • 2021-03-25
      • 2018-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多