1. 程式人生 > 實用技巧 >C++17 Fold Expressions

C++17 Fold Expressions

C++17 Fold Expressions

本文介紹C++17新特性摺疊表示式。文章示例程式碼通過MinGW編譯,巨集__cplusplus=201703

下面我們從一個模板函式sum開始,介紹摺疊表示式。

用摺疊表示式簡化以前的程式碼

C++11引入了變長引數模板,我們想求變長引數的和,可以這樣寫模板函式

template <typename T>
auto sum(T arg){
    return arg;
}

template <typename T1, typename... T>
auto sum(T1 arg, T... args){
    return arg + sum(args...);
}

int main() {
    std::cout<<sum(1,2,3)<<std::endl;
    return 0;
}

注:這裡用到了auto推導,C++14編譯沒問題。用C++11編譯的讀者記得在函式簽名後面加"-> T"

為了完成sum這個函式,我們需要寫2個函式。一個進行遞迴,一個作為遞迴返回條件。這種模板的遞迴是在編譯時發生的,遇到複雜的遞迴會大大加大編譯時間。有沒有辦法寫一個模板函式,同時又能實現sum功能呢?

有,就是摺疊表示式

我們看下摺疊表示式的寫法

template <typename... T>
auto sum_folder(T... args) {
    return (... + args);
}

int main() {
    std::cout<<sum_folder(1,2,3)<<std::endl;
    return 0;
}

這裡摺疊表示式會將sum_folder(1,2,3)擴充套件成(1+(2+3))

如何使用摺疊表示式

看了上面的例子,相信讀者對摺疊表示式已經有了直觀的認識。下面我們詳細介紹下摺疊表示式的使用。

一元摺疊

假設引數是args,操作符是op。一元摺疊有兩種情況:左摺疊和右摺疊

  1. unary left fold: (... op args) expends to ((arg1 op arg2) op arg3) + ...
  2. unary right fold: (args op ...) expends to arg1 op (arg2 op ... (argN-1 op argN))

舉2個例子方便理解

左摺疊

template<typename... T>
string combine_str_left(T... args) {
    return (... + args);
}

string s("head");
// expand to (s+" ") + "tail"
std::cout<<combine_str_left(s," ","tail")<<std::endl;

右摺疊

template<typename... T>
string combine_str_right(T... args) {
    return (args + ...);
}

右摺疊就不能combine_str_right(s," ", "tail")這麼寫,因為擴充套件開來是s + (" " + "tail")顯然兩個字面值是不能直接相加的。所以比起右摺疊,左摺疊用的比較多。

二元摺疊

  1. binary left fold: (value op ... op args) expand to ((value op arg1) op arg2) op ...
  2. binary right fold: (args op ... op value) expand to args1 op (arg2 op ... ( argN op value))