企业网站托管技巧,培训班网页设计,网站制作教程ppt,good建筑网站二十二、C17中的结构化绑定、std::optional、std::variant、std::any
本部分是一个小系列#xff0c;介绍C17中新引入的、用来解决各种不同返回情况的、标准库新组件。
1、C的结构化绑定 结构化绑定structured bindings是C17中引入的一项特性#xff0c;它允许开发者方便地…二十二、C17中的结构化绑定、std::optional、std::variant、std::any
本部分是一个小系列介绍C17中新引入的、用来解决各种不同返回情况的、标准库新组件。
1、C的结构化绑定 结构化绑定structured bindings是C17中引入的一项特性它允许开发者方便地从元组、结构体或数组中解包数据到单独的变量。是在元组(tuple)和对组(pairs)的基础上新扩展的一种处理多返回值的新方法。
下面例子是我用一个函数返回一个tuple元组我是如何取出元组中的各个元素的也就是如何解包的
其实在C中处理多个返回值我这篇博文 【C】C中如何处理多返回值、C中的模板、宏_如何在c 十十 中处理返回值?-CSDN博客 已经介绍过了好几种方法感兴趣的同学可以自行查看。这里的前两种方式不限于C标准的版本但是第三种结构化绑定只适用于C17标准。所以要使第三种解包方式顺利通过编译就得在visual studio的property页面里面设置为C17标准如上右图所示。
如果说本部分处理的都是确定的、多个返回值那么对于不确定个数的返回值如何处理呢就是下面的小标2如何处理optional数据。
2、如何存储可能存在也可能不存在的数据std::optional 对于返回值不确定时我们就得用std::optional了。std::optional也是C17标准中新引进的模板类类型用于处理那些可能存在也可能不存在的数据。要使用std::optional首先需要包含头文件。
比如我们现在要写一个函数这个函数的功能是读取一个文件那这个文件是否存在数据是否是我们期望的格式函数是否正常读取了这个文件此时这个函数的返回就是一个不确定的数据可能有返回数据也可能没有返回数据也可能需要返回多个数据。 如果正常读取了那就不用返回什么如果文件就不存在那就得返回一个能说明文件是存在还是不存在的东西如果文件格式不正确那得返回一个格式不正确的说明。所以函数的返回不是很确定的这种场景就得用std::optional了。
我们先写一个不用optional的函数 这种写法就很被动。当读取不成功时我们也不知道什么原因是路径错了还是格式错了还是路径格式都没错只是文件里面确实就是没数据所以啥也没读出来。下面我们看看使用optional能多大程度解决这些问题 可见使用optional代码要稍微清晰一些了如果文件没打开或者文件格式没对就没读到文件我们可以用value_or解释一下返回的空字符是怎么回事。 下面是optional操作符的简单介绍
3、如何在一个变量中存储多种类型的数据std::variant 这也是C17新标准库中提供给我们的模板类std::variant。它的作用是让我们不用担心处理的确切数据类型。 我们要做的就是指定一个叫做std::variant的类型然后列出它可能的数据类型。比如你正在解析一个文件你不确定这是一个字符串还是一个整数还是浮点数或者是布尔数你就把所有可能的类型都列出来。下面是variant的操作符
下面我们用代码来说明variant的用法
从上图variant类型对象的大小可以看出variant对象的大小是所有类型的大小之和。确切的说是内存对齐后的大小之和。可见variant是结构体或者类包装而来的。就是其实每种类型它都是分配了对应的内存空间了的。
而与variant非常相似的union可并不是这样的union分配的内存是所有可能类型数据中的最大那个类型的空间大小。所以variant和union是有本质区别的。也就是说variant是将所有可能的数据类型存储为单独的变量、作为单独的成员。而union则是所有可能的数据类型共享一个内存空间。
可见variant是给我们创建了一个结构体或类它只是将这可能的多种数据类型存储成那个类或者结构体的成员。 也所以从技术上讲union更有效率但variant更加类型安全不会造成未定义行为。
前面读取文件的例子我们使用optional也没有很完美的写出清晰的逻辑现在我用variant再写这个例子 此时是不是逻辑就清晰很多、代码也优雅很多这就是variant的使用场景。 4、如何存储任意类型的数据std::any 就是在C单个变量中存储任意类型的数据std::any这也是C17的全新处理方式。 std::variant是需要列出你可能用到的所有类型。而std::any是不需要声明任何类型 可见any类型的变量在声明和初始化时就可以完全不用管变量的类型只有当你要解码这个变量时才需要这个变量的真正的类型。
variant让我们列出所有可能用到的类型然后它背后是悄悄生成一个包含了所列的类型的结构体或者类所以variant是类型安全的。
而从any的源码看对于小类型small type(就是最底层的那些类型)any的底层和variant是完全相同的。对于大类型(就是复杂的类型)any会动态分配内存使用void*存储到大存储空间。动态分配内存不利于性能。就是说如果你在小类型上比如int, float,甚至vector类或者类似的比如math库等等使用variant或者any都一样因为它们都是相同的工作原理。但是如果你需要更多的存储空间any会动态分配但variant不会。话说回来就是variant在处理较大数据时会执行得更快因为避免了动态分配内存。
最后再展示一下any是如何动态分配内存的 超过32个字节any就开始动态分配内存了。所以any是来搞笑的吗一般不建议经常使用。