nprogram’s blog

気ままに、プログラミングのトピックについて書いていきます

構造化束縛 [C++17]

構造化束縛

C++17で追加された構造化束縛は多値を分解して受け取るための変数宣言の文法です。

多値を受け取るためには、これまでは多値をかたまりで受け取るか、ライブラリで分解して受け取るしかありませんでした。

構造化束縛を使うと、少ないコード量で多値を分解して受け取ることが可能です。

多値を受け取るコードの比較

#include <iostream>
#include <tuple>

std::tuple < int, double, std::string > get_tuple_value()
{
    return { 1, 2.0, "hello" };
}


int main(void){
    
    // 多値を受け取る方法(多値をかたまりで受け取る)
    auto result = get_tuple_value();
    std::cout << "b : " << std::get<0>(result) << std::endl;
    std::cout << "c : " << std::get<1>(result) << std::endl;
    std::cout << "d : " << std::get<2>(result) << std::endl;
    
    // 多値を受け取る方法(ライブラリで分解して受け取る)
    int param1;
    double param2;
    std::string param3;
    
    std::tie(param1, param2, param3) = get_tuple_value();
    std::cout << "b : " << param1 << std::endl;
    std::cout << "c : " << param2 << std::endl;
    std::cout << "d : " << param3 << std::endl;
    
    // 多値を受け取る方法(C++17)
    auto [b, c, d] = get_tuple_value();;
    
    std::cout << "b : " << b << std::endl;
    std::cout << "c : " << c << std::endl;
    std::cout << "d : " << d << std::endl;
}
b : 1
c : 2
d : hello
b : 1
c : 2
d : hello
b : 1
c : 2
d : hello

if文内、switch文内、range-based for文内で使用してみる

if, switch, range-based for文で使用する。

#include <iostream>
#include <tuple>
#include <map>
#include <vector>

int main(void){
    std::tuple<int, double, std::string> expr{5, 2.0, "test"s };    // "test"sとすることでstd::string型の文字列リテラルとなる
    
    // 構造化束縛はif文で使用可能です
    if ( auto[a, b, c] = expr ; a == 5 )    // 初期化文付き条件文 (C++17)
    {
        std::cout << "a : " << a << ", b : " << b << ", c : " << c << std::endl;
    }
    
    
    // 構造化束縛はswitch文で使用可能です
    switch ( auto[a, b, c]  = expr; a )    // 初期化文付き条件文 (C++17)
    {
        case 5:
            std::cout << "a : " << a << std::endl;
            std::cout << "b : " << b << std::endl;
            std::cout << "c : " << c << std::endl;
            break;
            
        default:
            break;
    }
    
    std::vector<std::tuple<int, double, std::string>> map_Prodct;
    map_Prodct.push_back(expr);
    map_Prodct.push_back(expr);
    map_Prodct.push_back(expr);
    map_Prodct.push_back(expr);
    map_Prodct.push_back(expr);            
    
    // 構造化束縛は[range-based for文]でも使用可能です
    for ( auto[a,b,c] : map_Prodct )
    {
        std::cout << "a : " << a << ", b : " << b << ", c : " << c << std::endl;
    }
}
a : 5, b : 2, c : test
a : 5
b : 2
c : test
a : 5, b : 2, c : test
a : 5, b : 2, c : test
a : 5, b : 2, c : test
a : 5, b : 2, c : test
a : 5, b : 2, c : test

使用例

#include <iostream>
using namespace std;
int main(void){
  {
    int ar[] = {3, 1, 4};

    // 配列を分解する。
    // ar[0]がaに代入され、
    // ar[1]がbに代入され、
    // ar[2]がcに代入される。
    // 分解する要素数は、配列の要素数と同じであること
    auto [a, b, c] = ar;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;
  }
  std::cout << std::endl;

  // 参照の例
  {
    int ar[] = {3, 1, 4};
    int (&rar)[3] = ar;
    auto [a, b, c] = rar;

    // ar[1]を値2に書き換える
    b = 2;

    std::cout << a << std::endl;
    std::cout << b << std::endl;
    std::cout << c << std::endl;
  }
}