std::variant
std::variant 是 C++17 中一个新加入标准函式库的 template 容器,使用时需要 #include
它的概念基本上是和 union 一样,是一个可以用来储存多种型别资料的容器;和 union 不同的是,std::variant 是 type-safe 的,再加上有许多函数可以搭配使用,所以在使用上应该算是相对安全
由于它是标准函式库的 template class,在使用时不需要另外去宣告一个新的类型
std::variant 在储存数据的时候,内部会有一个索引值来记录目前存储的是哪一个类型的数据
std::variant 基础用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| std::variant<int, double, std::string> x, y;
x = 1.0; y = "1.0"; x = 2;
std::cout << "x - " << x.index() << std::endl; std::cout << "y - " << y.index() << std::endl;
std::cout << std::get<int>(x) << std::endl; std::cout << std::get<double>(x) << std::endl; std::cout << std::get<2>(y) << std::endl; std::cout << std::get<1>(y) << std::endl;
int* i = std::get_if<int>(&x); if (i == nullptr) { std::cout << "wrong type" << std::endl; } else { std::cout << "value is " << *i << std::endl; }
|
std::visit
std::variant 的好搭档 std::visit,是 C++ 标准库中的一个函数,它的作用是将一个包含多种不同类型的可访问对象的容器中的对象传递给多个可调用对象中的一个,具体调用哪个可调用对象由该对象所包含的对象的实际类型决定;与直接使用 std::get 来获取值并手动判断其类型不同,std::visit 可以在编译时自动匹配相应的处理函数,清晰易读
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| std::variant<int, std::string> v;
v = "test";
std::visit([](auto&& arg) { std::cout << arg << '\n'; }, v);
v = 1; struct SOutput { void operator()(const int& i) { std::cout << i << std::endl; } void operator()(const std::string& s) { std::cout << s << std::endl; } }; struct SOutput { template<typename TYPE> void operator()(const TYPE& v) { std::cout << v << std::endl; } };
std::visit(SOutput(), v);
|
std::optional
std::optional 是一种 sum type,除了类型 T,它还有一个特殊的类型 std::nullopt_t 表示 “什么都没有” 的状态,这个类型与 std::nullptr_t 一样,只有一个值 std::nullopt,std::optional 在没有设置值的情况下类型就是 std::nulopt_t,值为 std::nullopt
std::optional 也提供了一系列和智能指针相似的接口:可以显式地转化为 bool 型变量来显示它此时是否拥有一个有意义的值;指针的解引用操作符 * 和 -> 也被重载,使用时需要注意它不会去检测是否 has_value(),也不会抛出异常,更加高效,但是要注意安全,当访问没有 value 的 std::optional 的时候,行为是未定义的
reset() 方法销毁存储在 std::optional 中的值,并将其值为空
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| std::optional<unsigned> opt = 2;
if (opt.has_value()) std::cout << *opt << std::endl;
std::cout << opt.value() << std::endl;
class A { public: int a = 0; }; int main() { A main_a; std::optional<A> opt = main_a; std::cout << opt.value().a << std::endl; if (opt) { std::cout << opt->a << std::endl; std::cout << (*opt).a << std::endl; } }
std::optional<unsigned> opt; if (!opt.has_value()) std::cout << opt.value_or(0) << ".\n"; std::cout << opt.value() << ".\n";
|
be slow to promise and quick to perform.