はじめに
プログラミングでは、複数のリストの要素をすべて組み合わせたパターンを網羅したい、という場面がよくあります。例えば、「サイズ(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の強力な新機能の一つです。