首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 變長模板參數包完整指南:語法、參數包展開與遞迴實作模式

     編輯:關於C++

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(型別可異質)
}

參數包展開模式

1. 遞迴展開(經典模式)

// 基礎案例:終止遞迴
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

2. 初始化列表展開(C++11 技巧)

template <class... Args>
void print_all(Args... args) {
    // 利用初始化列表求值順序保證
    (void)std::initializer_list<int>{ (std::cout << args << ' ', 0)... };
    std::cout << std::endl;
}

3. 折疊表達式(C++17 推薦)

// 一元右折疊
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)...

編譯器支援

  • C++11:變長模板、遞迴展開、初始化列表技巧
  • C++14:std::index_sequence、泛型 Lambda 捕獲包
  • C++17:折疊表達式、constexpr if 分支編譯期裁剪
  • C++20:std::type_identity、概念約束參數包
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved