您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關折疊表達式如何在C++中實現,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
C++11 提供了可變模板參數包, 使函數可以接受任意數量的參數. 但在 C++11中展開參數包稍顯麻煩, 而 C++17 的折疊表達式使得展開參數包變得容易, 其基本語法是使用 (…) 的語法形式進行展開。
支持的操作符
C++17中,折疊表達式支持 32 個操作符:
+, -, *, /, %, ^, &, |, =, <, >, <<, >>, +=, -=, *=, /=, %=, ^=, &=, |=, <<=, >>=,==, !=, <=, >=, &&, ||, ,, .*, ->*.
折疊分類
折疊位置
1.左折疊
2.右折疊
操作數個數
1.一元折疊
2.二元折疊
例 1: 左折疊
template <typename ... Ts> auto sum(Ts ... ts) { return (... + ts); } int res{sum(1, 2, 3, 4, 5)}; std::string a{"Hello "}; std::string b{"World"}; std::string str_res {sum(a, b)};//a+b的結果
例 2: 右折疊
template <typename ... Ts> auto sum(Ts ... ts) { return (ts + ...); }
例 1 中, 參數包 … 位于操作符的左側,故爾稱為左折疊。 如果 …位于操作符右側,則稱為右折疊,如例 2 所示。就例 1 與例 2 而言,左折疊與右折疊的效果是相同的。
int res {sum(1, 2, 3, 4, 5)}; //左折疊的展開方式為 1 + (2 + (3 + (4 + 5))), //右折疊的展開方式為 (((1 + 2) + 3) + 4) + 5 //在例 1 與 例 2 中,如果參數包包含的參數數量為 0,即為空包,會產生編譯錯誤,如 int the_sum {sum()}; /*大致的錯誤輸出如下 In instantiation of 'auto sum(Ts ...) [with Ts = {}]': error: fold of empty expansion over operator+ return (... + ts); */
若要解決空參數包的編譯錯誤,針對例 1,可以加上一個數值 0,可以解決編譯錯誤又可以使得語義不變,這個 0 相當于缺省值。通過加上一個數值,折疊就變成了二元折疊,如例 3 所示。
例 3: 二元折疊
template <typename ... Ts> auto sum(Ts ... ts) { // 二元右折疊 return (ts + ... + 0); // 二元左折疊 // return (0 + ... + ts); }
此時對于 int res{sum(1, 2, 3, 4, 5)};折疊的展開方式為
1 + (2 + (3 + (4 + (5 + 0))))
空參數包
空參數包就是參數包中不含任何參數。對于大多數操作符,空參數包將會引發編譯錯誤。對于 && 或 ||,空參數包是合法的,其中 && 的展開結果為 true,||的展開結果為 false。在逗號 , 操作符中,空參數包也合法,展開為 void()。
例 4: 計算指定區間內包含指定數值的個數
template <typename R, typename ... Ts> auto count(const R& range, Ts ... ts) { return (std::count(std::begin(range), std::end(range), ts) + ...); } ... std::vector<int> v {1, 2, 3, 4, 5}; count(v, 2, 5); // returns 2 count(v, 100, 200); // returns 0 count("abcdefg", 'x', 'y', 'z'); // returns 0 count("abcdefg", 'a', 'd', 'f'); // returns 3
例 5: 檢查插入多個元素是否成功
template <typename T, typename ... Ts> bool insert_all(T &set, Ts ... ts) { return (set.insert(ts).second && ...); } ... std::set<int> my_set {1, 2, 3}; insert_all(my_set, 4, 5, 6); // Returns true, my_set 值為 {1, 2, 3, 4, 5, 6} insert_all(my_set, 7, 2, 8); // Returns false, my_set 值為 {1, 2, 3, 4, 5, 6, 7} // 插入 2 時出錯, 8 不會被插入
最后
1.對于一元右折疊 (E op …) 具體展開為 E1 op (… op (EN-1 op EN))。
2.對于一元左折疊 (… op E) 具體展開為 (( E1 op E2) op …) op En。
3.對于二元右折疊 (E op … op I) 具體展開為 E1 op (… op (EN-1 op (EN op I)))。
4.對于二元左折疊 (I op … op E) 具體展開為 (((I op E1) op E2) op …) op E2。
左折疊與右折疊的語義并非總是相同的。比如對于加法和乘法,左折疊與右折疊的語義是相同的,但是對于減法與除法,其語義是不同的。
例 6: 左右折疊不同語義
template<typename... Args> auto left_sub(Args&&... args) { return (... - args); } template<typename... Args> auto right_sub(Args&&... args) { return (args - ...); } ... auto a = left_sub(2, 3, 4); // ((2 - ) -3 ) - 4) = -5 auto b = right_sub(2, 3, 4); // (2 - (3 - 4)) = 3
看完上述內容,你們對折疊表達式如何在C++中實現有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。