将"std::any"转换为"std::variant"



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

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

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


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

此代码获取一个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);
}

导螺杆上的代码


一些解释:

使用CCD_ 15是因为CCD_。

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

这是一个折叠表达式。为了更容易解释,我已经重命名了一些子表达式。重命名后,表达式变为:

// ((type_check && (any_cast, true)) || ...)
  • 如果type_checkfalse,则:
    • (any_cast, true)&&短路而未进行评估
    • (type_check && (any_cast, true))评估为false
    • 计算fold表达式中的下一个op
  • 如果CCD_ 23是CCD_
    • (any_cast, true)被评估:
      • CCD_ 26。变量从任意对象中获取值
      • any_cast结果被丢弃
      • 评估true
      • (any_cast, true)评估为true
    • (type_check && (any_cast, true))评估为true
    • 由于||短路,未对折叠的其余部分进行评估
    • 整个表达式(倍数(计算为true
  • 如果没有type_check评估为true,则整个表达式(倍数(评估为false

相关内容

  • 没有找到相关文章

最新更新