- C++服务器开发精髓
- 张远龙
- 1033字
- 2021-07-23 18:22:12
1.9 C++17结构化绑定
对于std::map容器,很多读者应该都很熟悉。map容器提供了一个insert方法,用于向 map 中插入元素,但是很少有人记得 insert 方法的返回值是什么类型。让我们看一下C++98/03提供的insert方法的签名:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_56_2.jpg?sign=1739692482-T8e4CRgPaC69vDDZPHwItyET3JfYbaC7-0-8ad8476e5c0e7baa1c11940ab6187751)
这里我们仅关心其返回值,这个返回值是 std::pair<T1,T2>类型。由于 map中元素的key不允许重复,所以如果 insert方法调用成功,则 T1是被成功插入 map中的元素的迭代器,T2的类型为bool,此时其值为true(表示插入成功);如果insert由于key重复,T1是造成插入失败、已经存在于 map中的元素的迭代器,则此时 T2的值为 false(表示插入失败)。
在C++98/03标准中可以使用 std::pair<T1,T2>的first和second属性分别引用 T1和T2的值。如下面的代码所示:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_56_3.jpg?sign=1739692482-ZDkYwGbKsKxz4svLcSUJ80OsQB5eOTLJ-0-f0289214dbe441cece8ef16a30d407e1)
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_57_1.jpg?sign=1739692482-AEXv0U0CeyNA5RsoMihcaAcJAYJeDHaw-0-7397243f07d09f1adada20e4b4804dd9)
以上代码太繁复了,我们可以使用auto关键字让编译器自动推导类型。
std::pair一般只能表示两个元素,在C++11标准中引入了std::tuple类型,有了这个类型,我们就可以放任意数量的元素了,原来需要被定义成结构体的POD对象,我们可以直接使用std::tuple表示。例如,对于下面表示用户信息的结构体:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_57_2.jpg?sign=1739692482-DhABCy8kZ5evrOygluWB6Hf13mRs93ws-0-130afcd9400cfa9de98247cc3fa0ea41)
我们不再需要定义struct UserInfo这样的对象,可以直接使用std::tuple表示:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_57_3.jpg?sign=1739692482-vPOtVmhA5euV2k1gGZt7CFh7odKmiYFi-0-b4434dc9331fd067846bc02cd7d3b97a)
从std::tuple中获取对应位置的元素时,可以使用std::get<N>,其中N是元素的序号(从0开始)。
与定义结构体相比,无论是通过std::pair的first、second还是std::tuple的std::get<N>方法来获取元素子属性,这些代码都是难以维护的,其根本原因是 first和second这样的命名不能做到见名知意。
C++17引入的结构化绑定(Structured Binding)将我们从这类代码中“解放”出来。结构化绑定使用的语法如下:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_1.jpg?sign=1739692482-kUdcaPiXOM1FuKMHC27XnhYzXEM4vSqY-0-e868aea1da4de53cd75794508daf593a)
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_2.jpg?sign=1739692482-Em7ZDiFpSddXI7rTjV8ClPuHoZ35vA2g-0-579a86fafb94c0f420e105389d6d52c7)
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_3.jpg?sign=1739692482-k3QcIxryZyfD39bj69r9oXWGSdEt82yM-0-d633e15cefd2cbcab5a4c0d9332d7599)
右边的expression可以是一个函数调用、花括号表达式或者支持结构化绑定的某个类型的变量。例如:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_4.jpg?sign=1739692482-3HFpifkGmPGV5d6np6fhdnTEH1lj9STt-0-c604b70379081f77e5f315c9b448de59)
这样,我们可以给用于绑定到目标的变量名(语法中的a、b、c)起一个有意义的名称。
需要注意的是,绑定名称a、b、c是绑定目标的一份拷贝,当绑定类型不是基础数据类型时,如果你的本意不是想要得到绑定目标的副本,则为了避免拷贝带来的不必要开销,建议使用引用;如果不需要修改绑定目标,则建议使用const引用。示例如下:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_5.jpg?sign=1739692482-FqC2xyLJjDfyWLRdud889hIGLAZWrMaV-0-c5fe5c9e8808ecce56c2ba9c93302b84)
结构化绑定(Structured Binding)是C++17引入的一个非常好用的语法特性。有了这种语法,在遍历像map这样的容器时,我们可以使用更简洁和清晰的代码去遍历这些容器:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_6.jpg?sign=1739692482-fTJBIKtPY9vdzvChRTWC1vkyYOFGBe2q-0-4308c04c40a8d4c124c5e1de106bad31)
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_59_1.jpg?sign=1739692482-OyfgHbCRFIAhTmbqGTF059okUkvtTO6g-0-f2c3420586b1b719c797555b32eccf4e)
在以上代码中,cityName 和 cityNumber 可以更好地反映这个 map 容器的元素内容。再来看一个例子,在某WebSocket网络库中有如下代码:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_59_2.jpg?sign=1739692482-JP1sXsoUbFHsMyiPOleRNfDEfOQgjqUc-0-cf0297d573397ead4f651bd146b03161)
在以上加粗代码行中,write函数的返回类型是std::pair<int,bool>,被绑定到written、failed这两个变量中。前者在写入成功的情况下表示实际写入的字节数,后者表示是否写入成功:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_59_3.jpg?sign=1739692482-5OUXjEC91icHJ0iRb2XHA38taHEzdvtt-0-79c381bde6f74bd999e3ff8d0e47f2b5)
结构化绑定的限制
用于结构化绑定的变量不能使用constexpr修饰或声明为static,例如:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_59_4.jpg?sign=1739692482-W9jvvwOacHpAz6nFpA0TSKLCjWdinBAS-0-3f3230cd6faba9168dff5f0ea06756c5)
有些编译器也不支持在Lamda表达式捕获列表中使用结构化绑定的语法。