- C++服務器開發精髓
- 張遠龍
- 1033字
- 2021-07-23 18:22:11
1.9 C++17結構化綁定
對于std::map容器,很多讀者應該都很熟悉。map容器提供了一個insert方法,用于向 map 中插入元素,但是很少有人記得 insert 方法的返回值是什么類型。讓我們看一下C++98/03提供的insert方法的簽名:

這里我們僅關心其返回值,這個返回值是 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的值。如下面的代碼所示:


以上代碼太繁復了,我們可以使用auto關鍵字讓編譯器自動推導類型。
std::pair一般只能表示兩個元素,在C++11標準中引入了std::tuple類型,有了這個類型,我們就可以放任意數量的元素了,原來需要被定義成結構體的POD對象,我們可以直接使用std::tuple表示。例如,對于下面表示用戶信息的結構體:

我們不再需要定義struct UserInfo這樣的對象,可以直接使用std::tuple表示:

從std::tuple中獲取對應位置的元素時,可以使用std::get<N>,其中N是元素的序號(從0開始)。
與定義結構體相比,無論是通過std::pair的first、second還是std::tuple的std::get<N>方法來獲取元素子屬性,這些代碼都是難以維護的,其根本原因是 first和second這樣的命名不能做到見名知意。
C++17引入的結構化綁定(Structured Binding)將我們從這類代碼中“解放”出來。結構化綁定使用的語法如下:



右邊的expression可以是一個函數調用、花括號表達式或者支持結構化綁定的某個類型的變量。例如:

這樣,我們可以給用于綁定到目標的變量名(語法中的a、b、c)起一個有意義的名稱。
需要注意的是,綁定名稱a、b、c是綁定目標的一份拷貝,當綁定類型不是基礎數據類型時,如果你的本意不是想要得到綁定目標的副本,則為了避免拷貝帶來的不必要開銷,建議使用引用;如果不需要修改綁定目標,則建議使用const引用。示例如下:

結構化綁定(Structured Binding)是C++17引入的一個非常好用的語法特性。有了這種語法,在遍歷像map這樣的容器時,我們可以使用更簡潔和清晰的代碼去遍歷這些容器:


在以上代碼中,cityName 和 cityNumber 可以更好地反映這個 map 容器的元素內容。再來看一個例子,在某WebSocket網絡庫中有如下代碼:

在以上加粗代碼行中,write函數的返回類型是std::pair<int,bool>,被綁定到written、failed這兩個變量中。前者在寫入成功的情況下表示實際寫入的字節數,后者表示是否寫入成功:

結構化綁定的限制
用于結構化綁定的變量不能使用constexpr修飾或聲明為static,例如:

有些編譯器也不支持在Lamda表達式捕獲列表中使用結構化綁定的語法。