【C++】views::cartesian_productで全組み合わせループを簡潔に書く方法

目次

はじめに

プログラミングでは、複数のリストの要素をすべて組み合わせたパターンを網羅したい、という場面がよくあります。例えば、「サイズ(S, M, L)」と「色(赤, 青)」の全組み合わせ(S-赤, S-青, M-赤, …)を処理するようなケースです。

従来、このような処理はforループを入れ子(ネスト)にして書く必要があり、組み合わせるリストが増えるほど、コードのネストが深くなり、読みにくくなっていました。

この問題を解決するのが、C++23で導入された std::views::cartesian_product です。このレンジアダプタは、複数のコンテナを受け取り、それらの要素の全ての組み合わせをタプルのように扱うことができる、特殊なビュー(view)を生成します。


【前提】C++23とは?

C++23(シーピープラスにーさん)は、2023年に正式化された、C++言語の比較的新しい規格です。std::views::cartesian_product はこのC++23で追加された機能のため、利用するにはC++23に対応した最新のコンパイラ(と、その機能を有効にするための設定)が必要になります。


cartesian_product を使ったサンプルコード

このコードは、3つの異なるコンテナ(vector, array, list)の全要素の組み合わせを、cartesian_product を使ってループ処理し、出力します。

完成コード

#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <ranges> // views::cartesian_product を使うために必要

using namespace std;

int main() {
    vector<int> numbers = {1, 2};
    array<string, 2> letters = {"A", "B"};
    list<string> symbols = {"+", "-"};

    // --- C++23 views::cartesian_product を使った方法 ---
    cout << "--- 全ての組み合わせ ---" << endl;
    for (const auto& [num, letter, sym] : views::cartesian_product(numbers, letters, symbols)) {
        cout << num << letter << sym << " ";
    }
    cout << endl;

    return 0;
}

実行結果

--- 全ての組み合わせ ---
1A+ 1A- 1B+ 1B- 2A+ 2A- 2B+ 2B- 

コードの解説

for (const auto& [num, letter, sym] : views::cartesian_product(numbers, letters, symbols))

これが cartesian_product を使ったループ処理の核心部分です。

  • views::cartesian_product(...): 引数として渡された複数のコンテナ (numbers, letters, symbols) の直積を表現するビューを返します。このビューは、{1, "A", "+"}, {1, "A", "-"}, {1, "B", "+"}, … というような、全組み合わせのタプルの集まりと考えることができます。
  • [num, letter, sym]: C++17で導入された「構造化束縛 (structured binding)」です。cartesian_product が生成した組み合わせタプル {1, "A", "+"} を受け取り、その最初の値を num に、2番目の値を letter に、3番目の値を sym という名前の変数に、それぞれ自動で分解して代入してくれます。

ネストしたforループとの比較

もし cartesian_product を使わずに同じことをしようとすると、以下のように3重のネストしたforループが必要になります。

// 従来の方法
for (int num : numbers) {
    for (const string& letter : letters) {
        for (const string& sym : symbols) {
            cout << num << letter << sym << " ";
        }
    }
}

cartesian_product を使えば、コンテナの数がどれだけ増えても、ネストが深くなることなく、フラットで読みやすいループを維持できます。


まとめ

今回は、C++23で導入された std::views::cartesian_product を使って、複数のコンテナの全組み合わせをスマートにループ処理する方法を解説しました。

  • std::views::cartesian_product(コンテナ1, コンテナ2, ...) で、組み合わせのビューを作成する。
  • 範囲for文と構造化束縛 [v1, v2, ...] を組み合わせて、各組み合わせを直接受け取る。

cartesian_product は、多重ループのネストを劇的に削減し、コードの可読性を大幅に向上させる、C++23の強力な新機能の一つです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次