プログラミング言語C++の次期標準C++2c(C++26)向けに提案されている展開文(Expansion statement)について。template for構文をもちいて本体処理を反復的にコンパイル時展開する。
2025-06-22追記:2025年6月会合にてP1306R5が採択され*1、C++2c言語仕様に展開文(Expansion statement)が導入される。あわせて P2996R13 C++ Reflection(→id:yohhoy:20250305)も採択済み*2。
// P1306R3: destructurable expression auto tup = std::make_tuple(0, 'a', 3.14); template for (auto elem : tup) std::println("{}", elem); // 下記コードに展開される auto&& tup = std::make_tuple(0, 'a', 3.14); { auto elem = std::get<0>(tup); std::println("{}", elem); } { auto elem = std::get<1>(tup); std::println("{}", elem); } { auto elem = std::get<2>(tup); std::println("{}", elem); }
// P1306R3: expansion-init-list template for (auto elem : {0, 'a', 3.14}) std::println("{}", elem); // 下記コードに展開される { auto elem = 0; std::println("{}", elem); } { auto elem = 'a'; std::println("{}", elem); } { auto elem = 3.14; std::println("{}", elem); }
C++2c向けに同時検討されているC++ Reflection機能と組み合わせると、全C++プログラマの夢(?)であった「列挙型の値から文字列への変換関数」をジェネリックに実装できる。
// P1306R3 + P2996(Reflection) + P3491(define_static_*) #include <meta> // P2996+P3491 #include <string_view> #include <type_traits> template <typename E> requires std::is_enum_v<E> constexpr std::string_view enum_to_string(E value) { // リフレクション(reflection)演算子^^ + enumerators_ofメタ関数(P2996) // 列挙型Eの列挙子リストをstd::vector<std::meta::info>で返す // define_static_arrayメタ関数(P3491) // コンパイル時vector<meta::info>から静的配列への参照(span)に変換 template for (constexpr auto e : std::define_static_array(std::meta::enumerators_of(^^E))) { // リフレクション値(reflection value) eの型 == std::meta::info // スプライス式(splice-expression) [:e:] により列挙子の値を取得 if (value == [:e:]) { // identifier_ofメタ関数 // 列挙子eの識別子(名前)をstd::string_viewで返す return std::meta::identifier_of(e); } } return "<unnamed>"; }
2025-12-26追記:上記のenum_to_string関数実装にstd::define_static_arrayメタ関数(→id:yohhoy:20250629)利用を追記。StackOverflowの回答 What is `template for` in C++26? も参照のこと。
template for構文においても通常のfor構文と同じくbreak文/continue文をサポートする。コンパイル時展開はbreak/continue制御によらず行われ、評価フェーズで実行パス分岐が行われることに注意。
// P1306R3 template for (auto v : {1,2,3,4,5,6,7,8,9}) { if (v % 2 == 0) continue; std::print("{} ", v); if (v % 5 == 0) break; } // 1 3 5
関連URL