迭代引數包

通常,我們需要對可變引數模板引數包中的每個元素執行操作。有很多方法可以做到這一點,並且使用 C++ 17 可以更輕鬆地讀取和寫入解決方案。假設我們只想列印包中的每個元素。最簡單的解決方案是遞迴:

Version >= C++ 11

void print_all(std::ostream& os) {
    // base case
}

template <class T, class... Ts>
void print_all(std::ostream& os, T const& first, Ts const&... rest) {
    os << first;
    
    print_all(os, rest...);
}

我們可以使用擴充套件器技巧,在單個函式中執行所有流式傳輸。這樣做的優點是不需要第二次過載,但缺點是可靠性低於恆星:

Version >= C++ 11

template <class... Ts>
void print_all(std::ostream& os, Ts const&... args) {
    using expander = int[];
    (void)expander{0,
        (void(os << args), 0)...
    };
}

有關其工作原理的說明,請參閱 TC 的優秀答案

Version >= C++ 17

使用 C++ 17,我們在我們的工具庫中獲得了兩個強大的新工具來解決這個問題。第一個是 fold-expression:

template <class... Ts>
void print_all(std::ostream& os, Ts const&... args) {
    ((os << args), ...);
}

第二個是 if constexpr,它允許我們在一個函式中編寫我們的原始遞迴解決方案:

template <class T, class... Ts>
void print_all(std::ostream& os, T const& first, Ts const&... rest) {
    os << first;

    if constexpr (sizeof...(rest) > 0) {        
        // this line will only be instantiated if there are further
        // arguments. if rest... is empty, there will be no call to
        // print_all(os). 
        print_all(os, rest...);
    }
}