c++ std::variant std::optional

std::variant 是c++17 引入的一个类型,其作用类似于C语言中的Union,但是比Union 的功能强大的多。
C语言中一个联合体Union 可以储存多种类型数据,但缺点有很多。比如:
1 没有可用的方法来判断Union中真实储存的类型,获取值时也是内存拷贝的结果,可能会存在问题。这就只能靠程序员人脑保证获取的值是有意义的。
2 只能储存基础数据类型,不能储存其他结构体

使用 std::variant

声明一个variant对象很容易,我们可以利用std::variant 和 std::vector 将不同类型的数据放到一起,形成类似弱类型语言的效果 (例如javascript),这一点将非常有用。

#include <variant>

   using value = std::variant<int, double, bool, std::string>;
   std::vector<value> values = {0, true, 3.1415926,"hello"};

如何取出一个std::variant对象的值呢?
有一系列的方法判断一个 std::variant 对象的类型, 例如

index() 方法, 返回 variant 对象类型index,

using value = std::variant<int, double, bool, std::string>;
    value test = string("123");
    std::cout << test.index()<< endl;  //3, index 从0 开始,此处类型值为std::string

当一个std::variant 对象没有被初始化的时候,会发生什么呢?会默认按照第一个类型进行初始化,那如果第一个类型没有默认的构造函数会怎么样呢?编译器会报错,为了解决这个问题,std::引入了 std::monostate 作为占位的类型。也可以使用它来替代一部分 std::optional 的功能。

holds_alternative<> 判断 variant 是否是某种特定类型

std::get<> 方法获取类型的值,类型不正确会抛exception,模板参数可以是类型,也可以是 index值, 但必须是常量值,因为模板是编译期推断

std::variant<int, float> v, w;
    v = 12; // v 含 int
    int i = std::get<int>(v);
    w = std::get<int>(v);
    w = std::get<0>(v); // 与前一行效果相同
    w = v; // 与前一行效果相同
//  std::get<double>(v); // 错误: [int, float] 中无 double
//  std::get<3>(v);      // 错误:合法下标值为 0 与 1

std::get_if<> 推荐使用的方法,大部分c++项目都是禁止try- catch 的,因此无异常版本更加实用。
该方法在类型不正确会返回空,输入和输出都是指针类型

原文章:


 

std::optional同样也是c++17引入的一种类联合的对象类型

std::optional对象只是包含对象的内部内存加上一个布尔标志。因此,大小通常比包含的对象大一个字节。对于某些包含的类型,甚至可能根本没有大小开销,前提是附加信息可以放在包含的对象中。没有分配堆内存。对象使用与所包含类型相同的对齐方式。

然而,std::optional对象不仅仅是向值成员添加布尔标志功能的结构。例如,如果没有值,就不会为所包含的类型调用构造函数(因此,可以为对象提供没有值的默认状态)。

与std:: variable <>和std::any一样,生成的任何对象都具有值语义。也就是说,复制被实现为一个深度复制,创建一个独立的对象,该对象带有标记,如果在它自己的内存中包含值,则包含值。复制一个std::optional<>而不包含值是廉价的;
使用包含的值复制std::optional<>与复制包含的类型/值一样便宜/昂贵。支持Move语义。

原文链接: