访问boost::variant &&std::variant

C++ variant与visit详解
本文详细介绍了C++中variant容器及其成员函数std::visit的使用方法,对比了boost库中的apply_visitor函数,并阐述了两者的异同。std::visit用于将给定的访问者应用于variant变量组,而apply_visitor则提供了更为灵活的应用方式。

std::visit

定义于头文件 <variant>

  

template <class Visitor, class... Variants>
constexpr /*see below*/ visit(Visitor&& vis, Variants&&... vars);

 (C++17 起)
   

将观览器 vis 应用到 variant 变量组 vars

等效于返回

std::invoke(std::forward<Visitor>(vis), std::get<is>(std::forward<Variants>(vars))...)

,其中 is...vars.index()... 。如同用 decltype 从返回的表达式推导返回类型。

若上述调用不是对于所有 variant 的所有可选项类型均为同一类型和值类别的合法表达式,则调用为病式。

参数

vis-一个接受每个 variant 的每个可能可选项的可调用 (Callable) 对象
vars-传递给观览器的 variant 列表

返回值

观览器的所选调用所返回的值,转换成所有可行的 std::invoke 表达式的共用类型。

异常

若任何 vars 中的 variant 为因异常无值( valueless_by_exception ),则抛出 std::bad_variant_access

复杂度

variant 的数量为零或一时,可调用对象的调用在常数时间内实现,即它不依赖 sizeof...(Types)

variant 的数量大于1,则可调用对象的调用没有复杂度要求。

 

函数 apply_visitor

boost::apply_visitor —

将给定的访问者应用到给定的 variant 的内容上,该过程在编译期进行类型安全检查,以确认所有类型均被访问者所处理。

 

摘要

template<typename Visitor, typename Variant> 
  typename Visitor::result_type 
  apply_visitor(Visitor & visitor, Variant & operand);
template<typename Visitor, typename Variant> 
  typename Visitor::result_type 
  apply_visitor(const Visitor & visitor, Variant & operand);
template<typename BinaryVisitor, typename Variant1, typename Variant2> 
  typename BinaryVisitor::result_type 
  apply_visitor(BinaryVisitor & visitor, Variant1 & operand1, 
                Variant2 & operand2);
template<typename BinaryVisitor, typename Variant1, typename Variant2> 
  typename BinaryVisitor::result_type 
  apply_visitor(const BinaryVisitor & visitor, Variant1 & operand1, 
                Variant2 & operand2);
template<typename Visitor> 
  apply_visitor_delayed_t<Visitor> apply_visitor(Visitor & visitor);

说明

apply_visitor 的行为取决于它所操作的参数的数量(即除访问者以外的其它参数)。该函数的行为如下:

  • 接受一个操作数的重载将以给定的 variant 操作数的内容调用给定的访问者的单参函数调用操作符。
  • 接受两个操作数的重载将以给定的 variant 操作数的内容调用给定的访问者的二元函数调用操作符。
  • 只接受一个访问者的重载将返回一个 泛型函数对象,该对象接受一个或两个参数并以这些参数和 visitor 调用 apply_visitor, 其行为和前面两项相似。(这种行为特别有用,例如当你需要对一个 variant 对象序列中的各个元素使用一个标准库算法时)。

 

返回: 接受操作数的重载将返回将给定访问者应用于给定操作数所得的结果。只接受一个访问者的重载则返回一个函数对象,以延后将访问者应用于任意操作数。 要求: 给定的访问者必须符合 StaticVisitor 概念的要求,并处理给定 variant 的各个有界类型。 抛出: 接受操作数的重载只会在给定的访问者抛出异常时抛出。只接受一个访问者的重载则不会抛出。(但是请注意,返回的 函数对象 有可能在运行时抛出)

<think>好的,用户问的是如何检查boost::variant是否包含有效值。我需要先回忆一下boost::variant的相关知识。根据引用3提到的,std::variant访问错误类型时会抛出异常,但boost::variant可能类似。用户可能需要知道如何判断variant当前存储的类型,或者是否存在有效值。 首先,boost::variant通常总是包含一个值,因为在构造时它必须被初始化为其中一个可能的类型。所以可能用户的问题其实是怎样判断当前存储的是哪个类型。或者是否存在未初始化的情况?不过根据引用1,传递给apply_visitor的variant变量应该是有效的,所以可能variant必须持有有效值。 但用户可能遇到的情况是,variant是否处于某种无效状态,比如在移动操作后?不过一般来说,boost::variant设计上是始终有效的。但用户可能误以为需要检查,所以需要解释如何确定当前存储的类型。 根据引用5中的static_visitor,可能需要用访问者模式来检查类型。或者使用which()方法获取当前类型的索引。或者使用get函数尝试获取,如果失败则抛出异常,但这样可能不是检查的有效方法。 查看引用3中的std::variant,提到用std::get或get_if来访问,这可能类似于boost::variant的方法。所以可能的检查方法包括: 1. 使用which()成员函数获取当前存储类型的索引。 2. 使用visitor来访问,但需要处理所有可能的类型。 3. 使用boost::get<T>()来尝试获取,如果返回nullptr则说明不是该类型。 所以正确的步骤应该是:variant实例总是包含有效值,但需要检查是否存储了特定类型。因此,用户的问题可能转化为如何判断当前存储的是哪一种类型。例如,使用variant.which()来获取索引,或者使用get<T>来判断是否存在。 另外,引用2提到boost::any需要可拷贝构造,但variant可能不同,但这里用户的问题是关于variant的。根据引用1中的例子,variant在构造时必须初始化,所以它总有一个有效值。因此,用户可能误解了variant的有效性,实际上不需要检查是否存在值,而是检查类型。 所以,正确的回答应该是:boost::variant始终包含有效值,但可以通过which()或apply_visitor来判断当前存储的类型。例如,使用which()返回当前类型的索引,或者用get<T>来尝试访问,如果失败则说明类型不匹配。 同时,需要引用相关的参考资料,比如引用3提到std::variant访问方式,可能类比到boost::variant。引用1中的apply_visitor可能也是一种方法。</think>要检查`boost::variant`是否包含有效值或确定当前存储的具体类型,可以通过以下方法实现: ### 1. **`boost::variant`始终包含有效值** `boost::variant`在构造时必须初始化,且始终包含其声明类型列表中的某一个具体值,因此不存在“无效值”状态[^1][^3]。若尝试未初始化或非法赋值,会在编译时或运行时抛出异常(如`boost::bad_get`)。 ### 2. **检查当前存储的具体类型** #### 方法一:使用`which()`成员函数 `variant.which()`返回当前存储类型的索引值(从0开始),对应声明时的类型顺序: ```cpp boost::variant<int, std::string, double> v = 42; if (v.which() == 0) { std::cout << "当前存储int类型"; } // 索引0对应int类型 ``` #### 方法二:使用`boost::get<T>()`模板函数 尝试通过`boost::get<T>()`获取值,若类型不匹配则返回空指针: ```cpp if (auto* p = boost::get<int>(&v)) { std::cout << "值为: " << *p; } else { std::cout << "非int类型"; } ``` #### 方法三:使用访问者模式(Visitor) 定义继承`boost::static_visitor<>`的访问者类,通过`boost::apply_visitor()`执行类型匹配操作: ```cpp struct MyVisitor : public boost::static_visitor<void> { void operator()(int x) const { /* 处理int类型 */ } void operator()(const std::string& s) const { /* 处理string类型 */ } void operator()(double d) const { /* 处理double类型 */ } }; boost::apply_visitor(MyVisitor{}, v); // 自动匹配当前类型 ``` ### 3. **异常处理** 若直接调用`boost::get<T>()`且类型不匹配,会抛出`boost::bad_get`异常: ```cpp try { int value = boost::get<int>(v); } catch (const boost::bad_get& e) { std::cerr << "类型错误: " << e.what(); } ``` ### 总结 `boost::variant`本身无需检查“有效性”,但需通过上述方法判断当前存储的具体类型,以确保安全访问[^3][^5]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值