C++ Learning

第50回 可変長テンプレート (Variadic Template)

関数や型に任意個の引数を渡せる仕組み。printf の型安全版、std::make_sharedvector::emplace_back など、標準ライブラリの便利機能はこれで作られています。

このページで押さえること
✅ 最低限ここだけ覚える
  • template<class... Args> で可変長
  • 関数で Args... args として受け取り、args... で転送
  • C++17 の fold expression (... + args)
  • emplace や make_unique/shared で日常的に恩恵
⭐ 余裕があれば読む
  • 再帰展開(古い書き方)
  • sizeof...(Args)
  • perfect forwarding との組合せ
  • 型リストメタプログラミング

1. 基本 ― 合計関数

昔の書き方再帰展開
// 終了条件 int sum() { return 0; } // 再帰展開 template<class T, class... Rest> T sum(T first, Rest... rest) { return first + sum(rest...); } sum(1, 2, 3, 4); // 10
C++17 fold簡潔
template<class... Args> auto sum(Args... args) { return (... + args); // fold expression } sum(1, 2, 3, 4); // 10 sum(1.0, 2, 3.5); // 6.5 (混在も OK)

(... + args)fold expression。引数を args[0] + args[1] + args[2] + ... のように展開します。

2. パラメータパックの基本

転送する(perfect forwarding)STL の定番
template<class T, class... Args> std::unique_ptr<T> make_unique_like(Args&&... args) { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); } // std::make_unique の実装そのもの

std::forward と組み合わせると、受け取った引数を左辺値/右辺値の区別を保ったまま別関数に渡せます。これが emplace 系関数の仕組み。

3. C++17 fold expression

単項 fold演算子のみ
template<class... Args> auto sum(Args... a) { return (... + a); // a0+a1+a2+... } template<class... Args> auto all(Args... a) { return (... && a); // a0 && a1 && ... } all(true, true, false); // false
二項 fold初期値あり
template<class... Args> auto sum(Args... a) { return (0 + ... + a); // 初期値 0 } sum(); // 0(引数なしでも動く) // 出力を複数個並べる fold もよくある template<class... Args> void print_all(Args... a) { ((std::cout << a << " "), ...); // カンマ演算子で並列 }

4. 日常で気づかず使う例

普段は意識しないが: emplace_back(1, "hello") のように複数引数を取れるのは variadic template のおかげ。内部で new T(1, "hello") に転送されています。
ここまでで基本は OK
STEP 8 は完了。次は STL アルゴリズム特集(目玉 4 章)へ。
広告スペース

確認クイズ

可変長テンプレートを 3 問で確認。

Q1. 可変長テンプレートのパラメータパック宣言として正しいのは?

template<class T[]>
template<class T*>
template<class... Args>
template<class ...Args> (スペース重要)
class... Args で任意個の型パラメータ。関数引数では Args... args、使う場所では args... で展開。

Q2. C++17 の fold expression (... + args) の役割は?

配列を初期化
パラメータパックを演算子で畳み込む(a0 + a1 + ...)
関数オーバーロード
可変長引数を配列化
fold expression は C++17 で導入。パックを指定した演算子で畳み込む。以前は再帰展開でゴリ押しだった処理が劇的に簡潔になりました。

Q3. std::make_unique<T>(1, "a", 3.14) のような任意個数の引数を受け取る実装の根幹は?

オーバーロード
デフォルト引数
可変長テンプレート + perfect forwarding
va_list マクロ
variadic template + std::forward で引数を型情報を保ったまま転送。これが emplace 系と make_unique/make_shared の仕組み。