C++17 详解 19 — std::any
本文为 《C++17 in detail》 一书的中文渣中渣译文,不足之处还望指正。
翻译太特么累人了……剩余部分还是只做摘要翻译吧。
8. std::any
std::optional 可以表示一个二态值:空值、非空值;
std::variant 表示一个指定类型集合内的类型;
std::any 更进一步,它可以存储任何类型。
综合用例:
1 | // Chapter Any/any_demo.cpp |
代码输出:
1 | 16 |
上边的例子向我们揭示了一些事实:
- std::any 跟 std::variant、std::optional 不同,它不是模版类。
- std::any 默认不包含任何值,可以通过 .has_value() 检查是否有值。
- 可以通过 .reset() 重置 std::any 对象。
- std::any 基于“退化了的”类型运行——所以在赋值、初始化或 emplace 之前类型会通过 std::decay 转换。
- 当使用一个其它类型赋值时,当前类型会被销毁。
- 可以使用
std::any_cast<T>
函数访问值,如果当前类型跟 T 不同会抛出 bad_any_cast 异常。 - 可以通过 .type() 获取当前类型,它返回当前类型的 std::type_info。
8.1 创建
- std::in_place_type 原地构造
1 | std::any a4{std::in_place_type<MyType>, 10, 11}; |
- std::make_any
1 | std::any a6 = std::make_any<std::string>("Hello World"); |
8.2 修改值
- emplace
1 | a.emplace<float>(100.5f); |
- std::any_cast
1 | std::any_cast<MyType&>(var).a = 11; |
1 | int* p = std::any_cast<MyType>(&var); |
std::any_cast 有多个重载版本,如上两个,可以返回持有类型的指针或引用。
8.3 访问存储值
只能通过 std::any_cast 访问 std::any。
8.4 性能 & 内存考量
std::any 因为意图存储任意类型,需要的内存空间是不确定的,所以需要动态分配内存。为了尽量避免动态内存分配,std::any 跟 std::string 一样采用了 SBO(Small Buffer Optimization),即预先分配若干字节的栈空间,仅当存储类型尺寸大于栈空间时才进行动态内存分配。