#1024程序员节|征文#
✨博客主页何曾参静谧的博客📌文章专栏「C/C++」C/C++程序设计📚全部专栏「VS」Visual Studio「C/C++」C/C++程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid函数说明
目录
std::variant详解
1. 引用头文件
std::variant是C++17引入的一种类型安全的联合体,用于存储多个可能类型中的一种值。要使用std::variant,首先需要包含头文件
#include <variant>
。
#include<variant>
2. 注意事项
std::variant
不允许存储引用、数组或void类型。std::variant
没有空的状态,每个构造好的std::variant对象至少调用了一次构造函数。- 如果
std::variant
的第一个类型没有默认构造函数,那么调用std::variant的默认构造函数会导致编译错误。此时,可以使用std::monostate作为第一个类型来确保std::variant能默认构造。 - 使用std::variant时,如果存储的类型有可能在语义上重叠或不明确(如std::variant<int, float>),需要特别注意操作和类型检查的准确性。
3. 函数构造
std::variant的构造函数允许通过直接赋值、std::in_place_type或std::in_place_index等方式进行初始化。
#include<iostream>#include<variant>#include<string>intmain(){
std::variant<int,double, std::string> v1 =42;// 直接赋值
std::variant<std::string,int> v2{std::in_place_type<std::string>,"Hello"};// 使用std::in_place_type
std::variant<std::string,int,float> v3{std::in_place_index<1>,66};// 使用std::in_place_index
std::cout << v1.index()<< std::endl;//当前属于的类型 输出: 0
std::cout << std::get<int>(v1)<< std::endl;// 输出: 42
std::cout << std::get<std::string>(v2)<< std::endl;// 输出: Hello
std::cout << std::get<int>(v3)<< std::endl;// 输出: 66return0;}
4. 对象初始化
std::variant对象可以通过直接赋值、构造函数初始化列表等方式进行初始化。
std::variant<int,double, std::string> v =3.14;// 直接赋值初始化
std::variant<std::string,int> w{"World"};// 使用构造函数初始化列表
5. 元素访问
访问std::variant中的元素可以使用std::get(variant)或std::get(variant),也可以使用std::visit进行更通用的访问。
#include<iostream>#include<variant>#include<string>intmain(){
std::variant<int,double, std::string> v ="Hello";// 使用std::get访问try{
std::cout << std::get<int>(v)<< std::endl;// 这将抛出异常}catch(const std::bad_variant_access& e){
std::cout <<"Error: "<< e.what()<< std::endl;// 输出: Error: bad variant access}// 使用std::get_if访问
std::cout << std::get_if<int>(&v)<< std::endl;// 输出: nullptr 0000000000000000
std::cout <<*(std::get_if<std::string>(&v))<< std::endl;// 输出: hello// 使用std::visit访问
std::visit([](auto&& arg){ std::cout << arg << std::endl;}, v);// 输出: Helloreturn0;}
6. 迭代器(不适用)
std::variant不支持迭代器,因为它不是容器类型,而是存储单一值的类型安全的联合体。
7. 容器(不适用)
虽然std::variant不能作为容器使用,但它可以存储容器类型,如
std::vector<int>
等。
std::variant<std::vector<int>, std::string> container = std::vector<int>{1,2,3};
8. 修改器
std::variant的值可以通过重新赋值进行修改。
std::variant<int,double, std::string> v =42;
v =3.14;// 修改为double类型
v ="Hello";// 修改为std::string类型
9. 元素比较
std::variant不支持直接比较,但可以通过std::visit和适当的比较逻辑来实现比较功能。
#include<iostream>#include<variant>#include<string>boolcompare_variants(const std::variant<int,double, std::string>& a,const std::variant<int,double, std::string>& b){return std::visit([](auto&& arg1,auto&& arg2){return arg1 == arg2;}, a, b);}intmain(){
std::variant<int,double, std::string> v1 =42;
std::variant<int,double, std::string> v2 ="42";// 注意这里是字符串类型// 比较会失败,因为类型不同if(!compare_variants(v1, v2)){
std::cout <<"v1 and v2 are not equal."<< std::endl;// 输出: v1 and v2 are not equal.}return0;}
10.其他用法
using var = std::variant<int,double, std::string>;
var value =1;int b =0;
b = std::get<int>(value);
总结
std::variant是C++17引入的一种类型安全的联合体,用于存储多个可能类型中的一种值。它提供了类型安全和便利的接口,相比传统的联合体(union)具有更高的安全性和灵活性。std::variant支持多种类型的存储和访问,可以通过std::get、std::visit等方式进行元素访问,同时提供了类型检查和异常处理机制。
应用场景
- 配置选项:在开发中,配置项可能需要支持多种数据类型(如整数、字符串、布尔值等)。使用std::variant可以简化配置管理,使得一个配置变量能够存储多种类型的配置值。
- 解析器:在编写如JSON解析器或其他形式的解析器时,数据结构可能需要存储不同类型的数据。std::variant提供了一种安全、灵活的方式来存储解析后的数据,从而简化代码并增强其健壮性。
- 状态机:在实现状态机时,每个状态可能需要不同类型的数据来描述。std::variant可以用来存储状态相关的数据,使得状态转换和数据处理更加灵活和安全。
- 命令模式:在实现命令模式时,如果命令的参数类型多样,std::variant可以作为一个通用的参数容器,提供统一的接口而隐藏实现细节。
通过了解和利用std::variant的这些特点和高级用法,可以在C++中更有效地处理那些需要存储和操作多种数据类型的场景,同时保持代码的整洁性和安全性。
版权归原作者 何曾参静谧 所有, 如有侵权,请联系我们删除。