先给个例子大家自行体会一下:
#include <iostream>
int main()
{
int a[2] = { 1, 2 };
auto [x, y] = a;
auto& [xr, yr] = a;
std::cout << x << " " << y << std::endl;
xr = 5;
std::cout << a[0] << " " << a[1] << std::endl;
return 0;
}
使用支持C++17标准的编译器进行编译,运行结果如下:

image.png
我们来一行一行的分析下这段代码:
int a[2] = { 1, 2 };
我们给一个有两个元素的数组赋值。auto [x, y] = a;
将这个数组的两个元素的值分别赋值给x,y。auto& [xr, yr] = a;
xr为a[0]的引用,yr为a[1]的引用。
其中auto [x, y] = a; auto& [xr, yr] = a;就是我们这次要讲的结构化绑定(structured binding)。什么是结构化绑定?
绑定指定的名字到初始化器的子对象或者元素。我们从上面的例子可以看出,这种方式既有可能是值的赋值,也有可能是引用,类似于别名(alias)。具体的语法
attr(optional) cv-auto ref-operator(optional) [ identifier-list ] = expression ; (1)
attr(optional) cv-auto ref-operator(optional) [ identifier-list ] { expression } ; (2)
attr(optional) cv-auto ref-operator(optional) [ identifier-list ] ( expression ) ; (3)
attr就是给表达式加一个或多个属性;
cv-auto加const,vol和auto等指示符;
ref-operator指的是&或者&&;
identifier-list为由该表达式引入的一系列的标识符,它们用逗号分隔,如上面例子中的x, y。
expression 为数组或者是非union的类类型,并且在expression的顶层不允许有逗号,即auto& [xr, yr] = {1, 2};是ill-formed
所以,将上面的例子改一下,一个比较完整的结构化绑定的表达式应该为
[[maybe_unused]] const auto& [xr, yr] = a;。
- 三种可能的绑定
- 绑定一个数组
即我们的例子中所演示的,identifier-list中元素的数量必须同数组元素的数量相同。
int a[3] = { 1, 2, 3 };
auto [x, y] = a; //error
编译结果
Error C3448 the number of identifiers must match the number of array elements or members in a structured binding ....
- 绑定一个类似于
tuple的类型
float x{};
char y{};
int z{};
std::tuple<float&,char&&,int> tpl(x,std::move(y),z);
const auto& [a,b,c] = tpl;
note:
-
std::tuple_size<E>::value是整型常量表达式,并且identifier-list的数量与这个值相等。 -
identifier-list中每个标识符的类型为std::tuple_element<i, E>::type,与对应的tuple元素相同。
- 绑定数据成员
struct S {
int x1 : 2;
volatile double y1;
};
S f();
const auto [x, y] = f();
identifier-list的数量要跟这个类的非静态成员变量的数量相等。
参考:https://en.cppreference.com/w/cpp/language/structured_binding