はじめに
C++で、std::pair
やstd::tuple
を返す関数を扱う際、従来はその戻り値を一度変数に受け取り、.first
やget<0>
を使って個々の要素にアクセスする必要があり、少し冗長でした。
C++17で導入された構造化束縛は、この問題をエレガントに解決します。auto [変数1, 変数2] = ...
という特別な構文を使うことで、オブジェクトの各要素を、宣言と同時に個別の名前を持つ変数に直接「束縛(bind)」できます。
【前提】C++17とは?
C++17は、2017年に正式化されたC++言語の規格です。構造化束縛はこのC++17で導入されたため、利用するにはC++17に対応したコンパイラが必要です。
構造化束縛のサンプルコード
このコードは、pair
、struct
、array
のそれぞれに対して、構造化束縛を使ってその要素を分解し、個別の変数として利用する例を示します。
完成コード
#include <iostream>
#include <string>
#include <tuple> // pair (tupleヘッダにも含まれることが多い)
#include <array>
using namespace std;
// 1. 構造体(struct)
struct UserProfile {
int id;
string name;
};
int main() {
cout << "--- pair ---" << endl;
pair<int, string> p = {101, "佐藤"};
// pairをidとnameに分解
auto [id, name] = p;
cout << "ID: " << id << ", 名前: " << name << endl;
cout << "\n--- struct ---" << endl;
UserProfile user = {202, "鈴木"};
// 構造体をuser_idとuser_nameに分解
auto [user_id, user_name] = user;
cout << "ID: " << user_id << ", 名前: " << user_name << endl;
cout << "\n--- 配列 ---" << endl;
int point[] = {30, 40};
// 配列をxとyに分解
auto [x, y] = point;
cout << "座標: (" << x << ", " << y << ")" << endl;
return 0;
}
コードの解説
auto [id, name] = p;
これが構造化束縛の構文です。
auto
: 型を自動推論するためのキーワードです。[...]
: 角括弧の中に、分解して受け取りたい変数名をカンマ区切りで列挙します。= p
: 右辺には、分解したいオブジェクトを置きます。
この一行は、内部的に以下のような処理を行っているのと似ています。 int id = p.first;
string name = p.second;
構造化束縛を使うことで、これがより簡潔で直感的に記述できます。
分解できる対象
構造化束縛は、主に以下の3種類のオブジェクトに対して機能します。
std::pair
,std::tuple
,std::array
: これらのテンプレートクラス。struct
やclass
: 全ての非静的メンバ変数がpublic
である場合に限る。- C言語スタイルの配列
参照 (&
) との組み合わせ
auto&
や auto&&
を使うことで、元のオブジェクトのメンバへの参照として束縛することも可能です。これにより、分解した変数を通じて、元のオブジェクトの値を変更できます。
pair<int, string> user = {301, "高橋"};
auto& [ref_id, ref_name] = user;
ref_id = 302; // 参照を介して値を変更
cout << "変更後のuser.first: " << user.first << endl; // -> 302
まとめ
今回は、C++17の構造化束縛を使って、pair
やstruct
などのオブジェクトを個別の変数に分解する方法を解説しました。
auto [v1, v2, ...]
という構文で、オブジェクトのメンバを分解できる。pair
,tuple
,struct
, 配列など、様々なオブジェクトに対応している。auto&
を使えば、元のオブジェクトへの参照として束縛できる。
構造化束縛は、複数の値を返す関数や、map
のループ処理など、様々な場面でコードを劇的に簡潔にし、可読性を向上させる、現代C++の必須テクニックです。