![C++服务器开发精髓](https://wfqqreader-1252317822.image.myqcloud.com/cover/623/39479623/b_39479623.jpg)
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=1739267432-qDnTwQDgUaY8tYcLLLMaGwf6J0yp7K9u-0-708501d697e880eff860c41f9e696cdc)
这里我们仅关心其返回值,这个返回值是 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=1739267432-rxuuHaAGn4Ljf8kKonH0kBmQuwe0GUwW-0-d0861f806652aba12a3bb9cb892cd3e2)
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_57_1.jpg?sign=1739267432-Jo0dUJI6owZp5asdrgbTu7FnMDgwJbS5-0-862ffb85ac7dd13078076d0f782cb789)
以上代码太繁复了,我们可以使用auto关键字让编译器自动推导类型。
std::pair一般只能表示两个元素,在C++11标准中引入了std::tuple类型,有了这个类型,我们就可以放任意数量的元素了,原来需要被定义成结构体的POD对象,我们可以直接使用std::tuple表示。例如,对于下面表示用户信息的结构体:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_57_2.jpg?sign=1739267432-NEMEkPjkGpYn8xkCfDwCdlmzw6iJleBO-0-aef82ef1ad2db06bd66e53a12eb26783)
我们不再需要定义struct UserInfo这样的对象,可以直接使用std::tuple表示:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_57_3.jpg?sign=1739267432-XJLyWqoFgPyAEGLWFey3jYEKMcWVM9Wh-0-7a0a5604d73477781af2e661b16ec10f)
从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=1739267432-qiqTkVj9nM9ByBXVy2RzS0ohJrLsdCKq-0-48b1d7e075291fedbdae440d51eec6d3)
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_2.jpg?sign=1739267432-8J84wWquSQbOnCCh1VuNnxhQfyBG0KT0-0-0c6b2d111dad4d006937ebed08b85229)
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_3.jpg?sign=1739267432-Df9iGPU7frNiJBrAJrhm3w2IA6gD7I6H-0-7be5556e15885602091c82a2f4a09e81)
右边的expression可以是一个函数调用、花括号表达式或者支持结构化绑定的某个类型的变量。例如:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_4.jpg?sign=1739267432-jULRz77NiUtw0z4bIlZhdEMKFamz5ewO-0-ea056bc2f932da709dd6a91f43418b1b)
这样,我们可以给用于绑定到目标的变量名(语法中的a、b、c)起一个有意义的名称。
需要注意的是,绑定名称a、b、c是绑定目标的一份拷贝,当绑定类型不是基础数据类型时,如果你的本意不是想要得到绑定目标的副本,则为了避免拷贝带来的不必要开销,建议使用引用;如果不需要修改绑定目标,则建议使用const引用。示例如下:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_5.jpg?sign=1739267432-MyhTzBsxr20aHd8aig9SOTEd49tY3tPU-0-5e0cd73c8502331100cf1c9c7a6d3838)
结构化绑定(Structured Binding)是C++17引入的一个非常好用的语法特性。有了这种语法,在遍历像map这样的容器时,我们可以使用更简洁和清晰的代码去遍历这些容器:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_58_6.jpg?sign=1739267432-NNXQVi9xSH8E81XPlR4N2OU1ia3QhVJE-0-7af53b2f2bd8aa37ea609441054cfd9c)
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_59_1.jpg?sign=1739267432-3LHvCIisnYDMjtsR5tdKy52zXEOyL91J-0-3a5ffa9d2e18b165eb182614b4ef0193)
在以上代码中,cityName 和 cityNumber 可以更好地反映这个 map 容器的元素内容。再来看一个例子,在某WebSocket网络库中有如下代码:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_59_2.jpg?sign=1739267432-4TegGPuARypcs0m77ZiirC5ZLJmLNBPu-0-4ecb850f78b11305ae67f1115291dfb4)
在以上加粗代码行中,write函数的返回类型是std::pair<int,bool>,被绑定到written、failed这两个变量中。前者在写入成功的情况下表示实际写入的字节数,后者表示是否写入成功:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_59_3.jpg?sign=1739267432-VtJFYtcngitRjeopGiVLHW9RpnlRO1lh-0-004042eaf899c44f1166fa9ca1e39c84)
结构化绑定的限制
用于结构化绑定的变量不能使用constexpr修饰或声明为static,例如:
![](https://epubservercos.yuewen.com/EE4394/20637464301305906/epubprivate/OEBPS/Images/41263_59_4.jpg?sign=1739267432-MTQb6bIJh80XYvnpll6E7vqBvvcBgJ6a-0-49b2bcd102308370623da4ed71a6e04d)
有些编译器也不支持在Lamda表达式捕获列表中使用结构化绑定的语法。