構造化束縛
CoddyのC++ジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 88/104。
C++17で導入された構造化 bindingsを使うと、配列、ペア、タプル、または構造体から複数の値を、1つの宣言で個別の名前付き変数に展開できます。これにより、複合データを扱うコードがより簡潔で読みやすくなります。
この構文では、角括弧内に新しい変数名を含めてautoを使用します:
#include <iostream>
#include <map>
#include <tuple>
int main() {
// ペアのアンパッキング
std::pair<std::string, int> person{"Alice", 25};
auto [name, age] = person;
std::cout << name << " is " << age << "\n";
// タプルのアンパッキング
std::tuple<int, double, char> data{42, 3.14, 'X'};
auto [num, pi, letter] = data;
// 範囲ベースのforループでのアンパッキング
std::map<std::string, int> scores{{"Bob", 90}, {"Carol", 85}};
for (const auto& [student, score] : scores) {
std::cout << student << ": " << score << "\n";
}
}構造化束縛は、配列やパブリックメンバーを持つカスタム構造体でも機能します。
struct Point {
double x;
double y;
};
Point getOrigin() { return {0.0, 0.0}; }
int main() {
auto [x, y] = getOrigin();
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;
}auto&またはconst auto&を使用して参照によるバインディングを行うと、コピーを避け、必要に応じて元の値を変更できます。この機能は、STLコンテナを反復処理するときや、複数の値を返す関数を扱うときに特に便利です。
チャレンジ
簡単構造化束縛の力を示す学生成績アナライザーを構築しましょう。学生の記録とコースデータを処理するシステムを作成し、コード全体で構造化束縛を使用して、pair、tuple、structを洗練された方法で展開します。
コードを3つのファイルに分けて整理します。
Student.h:学生の名前(std::string)、ID(int)、GPA(double)のpublicメンバーを持つStudentstructをDefineします。また、名前、ID、GPAを受け取り、Studentstructを返すcreateStudentというfunctionも作成します。GradeUtils.h:成績処理用のユーティリティfunctionを作成します。数値スコア(整数)を受け取り、3つの値、つまり文字による成績(
std::string)、成績ポイント(double)、および合格しているかどうか(bool)を含むstd::tupleを返すfunctiongetGradeInfoをDefineします。次の成績基準を使用します。- 90以上: "A", 4.0, true
- 80-89: "B", 3.0, true
- 70-79: "C", 2.0, true
- 60-69: "D", 1.0, true
- Below 60: "F", 0.0, false
さらに、コース名(
std::string)とスコア(int)を受け取り、それらの値のstd::pairを返すfunctionmakeScorePairもDefineします。main.cpp:4つのinputsを読み取ります。- 学生名(string)
- 学生ID(integer)
- コース名(string)
- スコア(integer)
main function全体で構造化束縛を使用します。
- 名前、ID、プレースホルダーGPAの0.0を指定して
createStudentをCallします。構造化束縛を使用して、返されたstructを個別の変数に展開し、次を出力します:Student: [name] (ID: [id]) - コース名とスコアを指定して
makeScorePairをCallします。構造化束縛を使用してpairを展開し、次を出力します:Course: [course], Score: [score] - スコアを指定して
getGradeInfoをCallします。構造化束縛を使用してtupleの3つの要素すべてを展開し、次を出力します。(合格がtrueの場合は "yes"、falseの場合は "no" を出力します)Grade: [letter] Points: [points] Passing: [yes/no]
たとえば、inputsがAlice、1001、Math、85の場合:
Student: Alice (ID: 1001)
Course: Math, Score: 85
Grade: B
Points: 3
Passing: yesinputsがBob、2002、Physics、55の場合:
Student: Bob (ID: 2002)
Course: Physics, Score: 55
Grade: F
Points: 0
Passing: no必要な箇所に<tuple>と<utility>をincludeすることを忘れないでください。重要なポイントは、構造化束縛によって、複合型、pair、tuple、structを、読みやすい1つの宣言で名前付き変数に展開できることです。
自分で試してみよう
#include <iostream>
#include <string>
#include "Student.h"
#include "GradeUtils.h"
int main() {
// 入力を読み取る
std::string studentName;
int studentId;
std::string courseName;
int score;
std::cin >> studentName;
std::cin >> studentId;
std::cin >> courseName;
std::cin >> score;
// TODO: name、id、およびプレースホルダーのGPA 0.0でcreateStudentを呼び出す
// 構造化束縛を使用して構造体をアンパックする: auto [name, id, gpa] = ...
// 出力: Student: [name] (ID: [id])
// TODO: コース名とスコアでmakeScorePairを呼び出す
// 構造化束縛を使用してペアをアンパックする: auto [course, sc] = ...
// 出力: Course: [course], Score: [score]
// TODO: スコアでgetGradeInfoを呼び出す
// 構造化束縛を使用してタプルをアンパックする: auto [letter, points, passing] = ...
// 出力:
// Grade: [letter]
// Points: [points]
// Passing: [yes/no] (passing が true の場合は "yes"、false の場合は "no" を出力)
return 0;
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
3コンストラクタとデストラクタ
デフォルトコンストラクタパラメータ付きコンストラクタコピーコンストラクタムーブコンストラクタコンストラクタ初期化リスト委譲コンストラクタデストラクタ徹底解説Rule of Three / Five / Zero復習 - Stringクラス6演算子オーバーロード
演算子オーバーロード入門算術演算子のオーバーロード比較演算子のオーバーロードストリーム演算子代入演算子のオーバーロード[] と () の演算子オーバーロード型変換演算子復習 - Matrixクラス自分で練習してみよう: C++オンラインコンパイラ