4.2 Fold Expressions
4.2 折疊表達式
Since C++17, there is a feature to compute the result of using a binary operator over all the arguments of a parameter pack (with an optional initial value).
從C++17開始,有一個特性可以使用二元運算符對參數包中的所有參數進行計算,以獲取結果(參數包可帶有可選的初始值)。
For example, the following function returns the sum of all passed arguments:
例如,下面的函數返回所有傳入的實參之和:
template<typename… T> auto foldSum (T… s) { return (… + s); // ((s1 + s2) + s3) … }
If the parameter pack is empty, the expression is usually ill-formed (with the exception that for operator && the value is true, for operator || the value is false, and for the comma operator the value for an empty parameter pack is void()).
如果是空參數包,則表達式通常是格式錯誤的(例外:如果使用運算符&&,則值為true。如果使用運算符||,則值為false。如果使用逗號運算符,則值為void())。
Table 4.1 lists the possible fold expressions.
表格4.1列出了所有可能的折疊表達式。

You can use almost all binary operators for fold expressions (see Section 12.4.6 on page 208 for details). For example, you can use a fold expression to traverse a path in a binary tree using operator ->*:
幾乎所有的二元運算符都可以用於折疊表達式(有關詳細信息,請參閱第208頁的12.4.6節)。例如,可以使用折疊表達式通過“->*”運算符沿一條路徑遍歷二叉樹。
// 定義二叉樹結構體和遍歷輔助函數: struct Node { int value; Node* left; Node* right; Node(int i = 0) : value(i), left(nullptr), right(nullptr) {} ... }; //成員指針 auto left = &Node::left; //等價於Node* Node::*left = &Node::left; auto right = &Node::right; //等價於Node* Node::*right = &Node::right; // 使用折疊表達式按指定路徑(paths)來遍歷二叉樹: template<typename T, typename... TP> Node* traverse(T np, TP... paths) { return (np->*…->*paths); // np ->* paths1 ->* paths2 … } int main() { //初始化二叉樹結構體: Node* root = new Node{ 0 }; root->left = new Node{ 1 }; root->left->right = new Node{ 2 }; ... //遍歷二叉樹 : Node* node = traverse(root, left, right); //從根節點開始,沿着向左再向右的路徑找出 //相應的節點(即,value為2的節點) ... }
Here, (np ->* … ->* paths) uses a fold expression to traverse the variadic elements of paths from np.
此外,(np->*…->*paths)利用折疊表達式從np節點開始,遍歷了路徑上數量不定的元素。
With such a fold expression using an initializer, we might think about simplifying the variadic template to print all arguments, introduced above:
對於使用初始化器那樣的一個折疊表達式,我們可能會考慮簡化可變參數模板來打印上面介紹的所有參數。
template<typename… Types> void print (Types const&… args) { (std::cout << … << args) << ‘\n’; }
However, note that in this case no whitespace separates all the elements from the parameter pack. To do that, you need an additional class template, which ensures that any output of any argument is extended by a space:
但是,要注意,在這種情況下,沒有用空格分隔參數包中的元素。為了做到這點,你需要一個額外的類模板,它可以確保任何參數的輸出都用空格擴展。
template<typename T> class AddSpace { private: T const& ref; //指向從構造函數中傳遞進來的參數 public: AddSpace(T const& r) : ref(r) { } friend std::ostream& operator<< (std::ostream& os, AddSpace<T> s) { return os << s.ref << ' '; // 輸出傳遞進來的參數和一個空格 } }; template<typename... Args> void print(Args... args) { (std::cout << ... << AddSpace(args)) << '\n'; }
Note that the expression AddSpace(args) uses class template argument deduction (see Section 2.9 on page 40) to have the effect of AddSpace<Args> (args), which for each argument creates an AddSpace object that refers to the passed argument and adds a space when it is used in output expressions.
注意, AddSpace(args)表達式使用了類模板參數推導(請參閱第40頁的2.9節)來產生AddSpace<Args>(args)的效果。它為每個參數創建一個指向該參數的AddSpace對象,在輸出表達式中使用該對象時會添加一個空格。
See Section 12.4.6 on page 207 for details about fold expressions.
關於折疊表達式更多的細節,請參閱第207頁的12.4.6節。
