Menu
Coddy logo textTech

構造化束縛

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コンテナを反復処理するときや、複数の値を返す関数を扱うときに特に便利です。

challenge icon

チャレンジ

簡単

構造化束縛の力を示す学生成績アナライザーを構築しましょう。学生の記録とコースデータを処理するシステムを作成し、コード全体で構造化束縛を使用して、pair、tuple、structを洗練された方法で展開します。

コードを3つのファイルに分けて整理します。

  • Student.h:学生の名前(std::string)、ID(int)、GPA(double)のpublicメンバーを持つStudent structをDefineします。また、名前、ID、GPAを受け取り、Student structを返すcreateStudentというfunctionも作成します。
  • GradeUtils.h:成績処理用のユーティリティfunctionを作成します。

    数値スコア(整数)を受け取り、3つの値、つまり文字による成績(std::string)、成績ポイント(double)、および合格しているかどうか(bool)を含むstd::tupleを返すfunction getGradeInfoを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を返すfunction makeScorePairもDefineします。

  • main.cpp:4つのinputsを読み取ります。
    1. 学生名(string)
    2. 学生ID(integer)
    3. コース名(string)
    4. スコア(integer)

    main function全体で構造化束縛を使用します。

    1. 名前、ID、プレースホルダーGPAの0.0を指定してcreateStudentをCallします。構造化束縛を使用して、返されたstructを個別の変数に展開し、次を出力します:Student: [name] (ID: [id])
    2. コース名とスコアを指定してmakeScorePairをCallします。構造化束縛を使用してpairを展開し、次を出力します:Course: [course], Score: [score]
    3. スコアを指定してgetGradeInfoをCallします。構造化束縛を使用してtupleの3つの要素すべてを展開し、次を出力します。
      Grade: [letter]
      Points: [points]
      Passing: [yes/no]
      (合格がtrueの場合は "yes"、falseの場合は "no" を出力します)

たとえば、inputsがAlice1001Math85の場合:

Student: Alice (ID: 1001)
Course: Math, Score: 85
Grade: B
Points: 3
Passing: yes

inputsがBob2002Physics55の場合:

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;
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: C++オンラインコンパイラ