C++11 引入變長模板,允許模板接受任意數量參數。本文從基礎語法到進階參數包展開技巧,系統講解變長模板核心機制與實戰模式。
template <class... Args> // 模板參數包
void func(Args... args); // 函式參數包
Args:模板參數包(型別序列)args:函式參數包(值序列)sizeof...(Args):參數包大小(編譯期常數)template <class... Args>
int count_args(Args... args) {
return sizeof...(args); // 或 sizeof...(Args)
}
int main() {
count_args(1, 2, 3, 4, 5, 6); // 返回 6
count_args(); // 返回 0(空參數包合法)
count_args('a', 3.14, "hello"); // 返回 3(型別可異質)
}
// 基礎案例:終止遞迴
void print() {
std::cerr << "EMPTY" << std::endl;
}
// 遞迴案例:剝離首參數,遞迴處理剩餘
template <class Head, class... Tail>
void print(Head head, Tail... tail) {
std::cerr << "Arg: " << head << std::endl;
print(tail...); // 參數包展開
}
// 呼叫: print(1, 2, 3, 4, 5, 6);
// 輸出: Arg: 1 ... Arg: 6 ... EMPTY
template <class... Args>
void print_all(Args... args) {
// 利用初始化列表求值順序保證
(void)std::initializer_list<int>{ (std::cout << args << ' ', 0)... };
std::cout << std::endl;
}
// 一元右折疊
template <class... Args>
void print_fold(Args... args) {
(std::cout << ... << args) << std::endl; // ((cout << a1) << a2) ...
}
// 二元左折疊(加總)
template <class... Args>
auto sum(Args... args) {
return (args + ... + 0); // ((a1 + a2) + ...) + 0
}
// 逗號折疊(執行多個運算式)
template <class... Funcs, class... Args>
void invoke_all(Funcs... funcs, Args... args) {
(funcs(args...), ...); // f1(args...), f2(args...), ...
}
template <bool... Flags>
int count_true() {
return (static_cast<int>(Flags) + ... + 0); // C++17 折疊
}
// 呼叫: count_true<true, false, true, false>(); // 返回 2
#include <tuple>
#include <utility>
// 將參數包存入 tuple 並按索引存取
template <class... Args>
void process_by_index(Args... args) {
auto tup = std::make_tuple(args...);
// 需配合 std::index_sequence 遍歷
[&]<std::size_t... Is>(std::index_sequence<Is...>) {
(std::cout << std::get<Is>(tup) << ' ', ...);
}(std::index_sequence_for<Args...>{});
std::cout << std::endl;
}
template <class F, class... Args>
decltype(auto) invoke(F&& f, Args&&... args) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
// 保持值類別(lvalue/rvalue)與 const/volatile 屬性
| 陷阱 | 說明 | 解決 |
|---|---|---|
| 參數包無法直接索引 | args[0] 錯誤 | 用 tuple、遞迴、折疊表達式 |
| 空參數包導致語法錯誤 | func(args...) 在空包時變 func() | 提供基礎案例重載或用折疊表達式 |
| 參數包展開位置錯誤 | 展開需在完整運算式內 | 遵循 pattern ... 語法規則 |
| 完美轉發遺漏 | 通用參考未 std::forward | 必加 std::forward<Args>(args)... |
std::index_sequence、泛型 Lambda 捕獲包constexpr if 分支編譯期裁剪std::type_identity、概念約束參數包