news 2026/7/2 11:07:15

结构化绑定

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
结构化绑定

stl 的 map 容器很多读者应该都很熟悉,map 容器提供了一个insert方法,我们用该方法向 map 中插入元素,但是应该很少有人记得insert方法的返回值是什么类型,让我们来看一下 C++98/03 提供的insert方法的签名:

std::pair<iterator,bool> insert( const value_type& value );

这里我们仅关心其返回值,这个返回值是一个std::pair<T1, T2>类型,由于 map 中的元素的 key 不允许重复,所以如果 insert 方法调用成功,T1 是被成功插入到 map 中的元素的迭代器,T2 的类型为 bool,此时其值为 true(表示插入成功);如果 insert 由于 key 重复,T1 是造成 insert 插入失败、已经存在于 map 中的元素的迭代器,此时 T2 的值为 false(表示插入失败)。

在 C++98/03 标准中我们可以使用std::pair<T1, T2>firstsecond属性来分别引用 T1 和 T2 的值。如下面的我们熟悉的代码所示:

#include <iostream> #include <string> #include <map> int main() { std::map<std::string, int> cities; cities["beijing"] = 0; cities["shanghai"] = 1; cities["shenzhen"] = 2; cities["guangzhou"] = 3; //for (const auto& [key, value] : m) //{ // std::cout << key << ": " << value << std::endl; //} //这一行在 C++11 之前写法实在太麻烦了, //std::pair<std::map<std::string, int>::iterator, int> insertResult = cities.insert(std::pair<std::string, int>("shanghai", 2)); //C++11中我们写成: auto insertResult = cities.insert(std::pair<std::string, int>("shanghai", 2)); std::cout << "Is insertion successful ? " << (insertResult.second ? "true" : "false") << ", element key: " << insertResult.first->first << ", value: " << insertResult.first->second << std::endl; return 0; }

代码19行实在太麻烦了,我们使用 auto 关键字让编译器自动推导类型。

std::pair一般只能表示两个元素,C++11 标准中引入了std::tuple类型,有了这个类型,我们就可以放任意个元素了,原来需要定义成结构体的 POD 对象我们可以直接使用std::tuple表示,例如下面表示用户信息的结构体:

struct UserInfo { std::string username; std::string password; int gender; int age; std::string address; }; int main() { UserInfo userInfo = { "Tom", "123456", 0, 25, "Pudong Street" }; std::string username = userInfo.username; std::string password = userInfo.password; int gender = userInfo.gender; int age = userInfo.age; std::string address = userInfo.address; return 0; }

我们不再需要定义 struct UserInfo 这样的对象,可以直接使用std::tuple表示:

int main() { std::tuple<std::string, std::string, int, int, std::string> userInfo("Tom", "123456", 0, 25, "Pudong Street"); std::string username = std::get<0>(userInfo); std::string password = std::get<1>(userInfo); int gender = std::get<2>(userInfo); int age = std::get<3>(userInfo); std::string address = std::get<4>(userInfo); return 0; }

std::tuple中获取对应位置的元素,我们使用std::get<N>,其中 N 是元素的序号(从 0 开始)。

与定义结构体相比,通过std::pairfirstsecond还是std::tuplestd::get<N>方法来获取元素子属性,这些代码都是非常难以维护的,其根本原因是firstsecond这样的命名不能做到见名知意。

C++17 引入的结构化绑定(Structured Binding )将我们从这类代码中解放出来。结构化绑定使用语法如下:

auto [a, b, c, ...] = expression; auto [a, b, c, ...] { expression }; auto [a, b, c, ...] ( expression );

右边的expression可以是一个函数调用、花括号表达式或者支持结构化绑定的某个类型的变量。例如:

//形式1 auto [iterator, inserted] = someMap.insert(...); //形式2 double myArray[3] = { 1.0, 2.0, 3.0 }; auto [a, b, c] = myArray; //形式3 struct Point { double x; double y; }; Point myPoint(10.0, 20.0); auto [myX, myY] = myPoint;

这样,我们可以给用于绑定到目标的变量名(语法中的abc)起一个有意义的名字。

需要注意的是,绑定名称abc是绑定目标的一份拷贝,当绑定类型不是基础数据类型时,如果你的本意不是想要得到绑定目标的副本,为了避免拷贝带来的不必要开销,建议使用引用,如果不需要修改绑定目标建议使用 const 引用。示例如下:

double myArray[3] = { 1.0, 2.0, 3.0 }; auto& [a, b, c] = myArray; //形式3 struct Point { double x; double y; }; Point myPoint(10.0, 20.0); const auto& [myX, myY] = myPoint;

结构化绑定(Structured Binding )是 C++17 引入的一个非常好用的语法特性。有了这种语法,在遍历像 map 这样的容器时,我们可以使用更简洁和清晰的代码去遍历这些容器了:

std::map<std::string, int> cities; cities["beijing"] = 0; cities["shanghai"] = 1; cities["shenzhen"] = 2; cities["guangzhou"] = 3; for (const auto& [cityName, cityNumber] : cities) { std::cout << cityName << ": " << cityNumber << std::endl; }

上述代码中cityNamecityNumber可以更好地反映出这个 map 容器的元素内容。

我们再来看一个例子,某 WebSocket 网络库(https://github.com/uNetworking/uWebSockets)中有如下代码:

std::pair<int, bool> uncork(const char *src = nullptr, int length = 0, bool optionally = false) { LoopData *loopData = getLoopData(); if (loopData->corkedSocket == this) { loopData->corkedSocket = nullptr; if (loopData->corkOffset) { /* Corked data is already accounted for via its write call */ auto [written, failed] = write(loopData->corkBuffer, loopData->corkOffset, false, length); loopData->corkOffset = 0; if (failed) { /* We do not need to care for buffering here, write does that */ return {0, true}; } } /* We should only return with new writes, not things written to cork already */ return write(src, length, optionally, 0); } else { /* We are not even corked! */ return {0, false}; } }

代码的第9write函数返回类型是std::pair<int, bool>,被绑定到[written, failed]这两个变量中去。前者在写入成功的情况下表示实际写入的字节数,后者表示是否写入成功。

std::pair<int, bool> write(const char *src, int length, bool optionally = false, int nextLength = 0) { //具体实现省略... }

结构化绑定的限制

结构化绑定不能使用constexpr修饰或被申明为 static,例如:

//正常编译 auto [first, second] = std::pair<int, int>(1, 2); //无法编译通过 //constexpr auto [first, second] = std::pair<int, int>(1, 2); //无法编译通过 //static auto [first, second] = std::pair<int, int>(1, 2);

有些编译器也不支持在 lamda 表达式捕获列表中使用结构化绑定语法。关于 lamda 表达式,我们将在下面的小节中介绍。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 11:04:36

KMX63与PIC18LF47K40在HMI手势交互中的应用

1. 从KMX63与PIC18LF47K40看现代HMI设计范式 当KMX63三轴加速度计遇上PIC18LF47K40微控制器&#xff0c;这个组合在工业控制面板上实现了手势唤醒功能——这正是当代人机界面&#xff08;HMI&#xff09;进化的缩影。传统按钮正在被自然交互方式取代&#xff0c;就像智能手机用…

作者头像 李华
网站建设 2026/7/2 11:04:14

HsMod:55项功能扩展全方位重塑你的炉石传说游戏体验

HsMod&#xff1a;55项功能扩展全方位重塑你的炉石传说游戏体验 【免费下载链接】HsMod Hearthstone Modification Based on BepInEx 项目地址: https://gitcode.com/GitHub_Trending/hs/HsMod 在炉石传说的世界里&#xff0c;每位玩家都渴望获得更流畅、更个性化的游戏…

作者头像 李华
网站建设 2026/7/2 11:02:01

ESP芯片烧录神器:esptool.py完整指南 - 5分钟快速上手

ESP芯片烧录神器&#xff1a;esptool.py完整指南 - 5分钟快速上手 【免费下载链接】esptool Serial utility for flashing, provisioning, and interacting with Espressif SoCs 项目地址: https://gitcode.com/gh_mirrors/es/esptool esptool.py是乐鑫科技&#xff08;…

作者头像 李华
网站建设 2026/7/2 10:59:01

Selenium WebDriver在.NET 4.8.1 ClickOnce部署中的五大痛点与解决方案

1. 项目概述&#xff1a;当Selenium WebDriver遇上.NET 4.8.1 ClickOnce如果你是一名使用C#和.NET Framework 4.8.1进行桌面应用开发的工程师&#xff0c;并且正在尝试将Selenium WebDriver自动化测试功能集成到你的应用中&#xff0c;然后通过ClickOnce部署给用户&#xff0c;…

作者头像 李华
网站建设 2026/7/2 10:58:26

期货反向跟单:好数据,未必能跟出好结果

期货反向跟单有一个很多人都想不通的悖论&#xff1a;手里筛选的盘手历史数据完全没问题&#xff0c;长期稳定亏损、是标准的优质反向标的&#xff0c;但最后跟单账户一合计却偏偏赚不到钱&#xff0c;甚至大幅亏损。其实核心问题不在盘手数据&#xff0c;而是绝大多数人都栽在…

作者头像 李华
网站建设 2026/7/2 10:54:09

WinAsar:3分钟掌握Electron asar文件的高效管理技巧

WinAsar&#xff1a;3分钟掌握Electron asar文件的高效管理技巧 【免费下载链接】WinAsar Portable and lightweight GUI utility to pack and extract asar( Electron archive ) files, Only 551 KB! 项目地址: https://gitcode.com/gh_mirrors/wi/WinAsar 你是否曾为E…

作者头像 李华