12.5 結構化綁定
10.11 用 pair 綁資料,拆開時 first、second 寫到手軟:
✘ 囉唆寫法:
pair<int, char> p = {7, 'A'};
int num = p.first;
char ch = p.second;
C++17 的結構化綁定(structured binding)一句話拆完:
✔︎ 省力寫法:
auto [num, ch] = p; // num 拿到 first、ch 拿到 second
中括號裡列出新變數的名字,由左到右依序對應 pair 的成員;每個變數的型態由對應成員決定(num 是 int、ch 是 char)——型態各自不同、又不用你寫,正是 12.2「讓編譯器推」的完美舞台(這裡也只能寫 auto,不能寫 int [num, ch])。變數個數必須跟成員個數一樣,多一個少一個都是編譯錯誤。
¶主戰場:掃 vector
結構化綁定跟 12.4 的 range-based for 是天作之合。「一串(身高,編號)」排序後輸出:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<pair<int, int>> v(n); // (身高, 編號)
for (auto &[h, id] : v) cin >> h >> id; // 加 &:直接讀進 v 的元素裡
sort(v.begin(), v.end()); // 10.11 的比較規則:先比 first
for (auto [h, id] : v) cout << h << ' ' << id << '\n';
return 0;
}
執行結果(輸入 3 與 170 1、155 2、160 3):
155 2
160 3
170 1
對照沒有結構化綁定的版本——迴圈裡滿地 v[i].first、v[i].second——哪個好讀一目瞭然。開場那份高手程式碼的中段,到這裡已經全部解鎖。
¶複本還是別名?跟 range-based for 同一套規則
#include <bits/stdc++.h>
using namespace std;
int main() {
pair<int, int> p = {3, 5};
auto [a, b] = p; // 不加 &:a、b 是成員的複本
a = 99;
cout << p.first << '\n';
auto &[x, y] = p; // 加 &:x、y 是成員的別名
x = 99;
cout << p.first << '\n';
return 0;
}
執行結果:
3
99
規則跟 12.3、12.4 一脈相承:預設複本,要寫入就加 &。上面讀入範例的 for (auto &[h, id] : v),兩個 & 的理由是同一個。
¶不只 pair:array 也拆得開
結構化綁定不是 pair 的專利,10.12 的 array 一樣可以拆——名字由左到右對應格子:
#include <iostream>
#include <array>
using namespace std;
int main() {
array<int, 3> p = {10, 20, 30};
auto [x, y, z] = p; // 三個名字對三格
cout << x << ' ' << y << ' ' << z << '\n';
return 0;
}
執行結果:
10 20 30
名字的個數必須跟格數一樣:寫成 auto [x, y] = p; 會直接編譯錯誤(only 2 names provided for structured binding),跟 pair 少寫一個是同一種錯。原生陣列 int p[3] 也適用。
掃 vector<array<int, 3>> 時就跟上面掃 vector<pair> 一模一樣:for (auto &[a, b, c] : v),要改元素照樣加 &。不過競程九成的用途還是拆 pair。
動手試試看:解掉重新排列——把每行的 (p_i, a_i) 存成 vector<pair<int, int>>,照 p_i 排序後依序輸出 a_i。讀入、排序、輸出三段全部用本節與 12.4 的寫法,練成一套流暢的組合技。