C++17中的折疊表達(dá)式實(shí)現(xiàn)
前言
C++11 提供了可變模板參數(shù)包, 使函數(shù)可以接受任意數(shù)量的參數(shù). 但在 C++11中展開參數(shù)包稍顯麻煩, 而 C++17 的折疊表達(dá)式使得展開參數(shù)包變得容易, 其基本語法是使用 (…) 的語法形式進(jìn)行展開。
支持的操作符
C++17中,折疊表達(dá)式支持 32 個(gè)操作符:
+, -, *, /, %, ^, &, |, =, <, >, <<, >>, +=, -=, *=, /=, %=, ^=, &=, |=, <<=, >>=,==, !=, <=, >=, &&, ||, ,, .*, ->*.
折疊分類
折疊位置
1.左折疊
2.右折疊
操作數(shù)個(gè)數(shù)
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的結(jié)果
例 2: 右折疊
template <typename ... Ts>
auto sum(Ts ... ts)
{
return (ts + ...);
}
例 1 中, 參數(shù)包 … 位于操作符的左側(cè),故爾稱為左折疊。 如果 …位于操作符右側(cè),則稱為右折疊,如例 2 所示。就例 1 與例 2 而言,左折疊與右折疊的效果是相同的。
int res {sum(1, 2, 3, 4, 5)};
//左折疊的展開方式為
1 + (2 + (3 + (4 + 5))),
//右折疊的展開方式為
(((1 + 2) + 3) + 4) + 5
//在例 1 與 例 2 中,如果參數(shù)包包含的參數(shù)數(shù)量為 0,即為空包,會產(chǎn)生編譯錯(cuò)誤,如
int the_sum {sum()};
/*大致的錯(cuò)誤輸出如下
In instantiation of 'auto sum(Ts ...) [with Ts = {}]':
error: fold of empty expansion over operator+
return (... + ts);
*/
若要解決空參數(shù)包的編譯錯(cuò)誤,針對例 1,可以加上一個(gè)數(shù)值 0,可以解決編譯錯(cuò)誤又可以使得語義不變,這個(gè) 0 相當(dāng)于缺省值。通過加上一個(gè)數(shù)值,折疊就變成了二元折疊,如例 3 所示。
例 3: 二元折疊
template <typename ... Ts>
auto sum(Ts ... ts)
{
// 二元右折疊
return (ts + ... + 0);
// 二元左折疊
// return (0 + ... + ts);
}
此時(shí)對于 int res{sum(1, 2, 3, 4, 5)};折疊的展開方式為
1 + (2 + (3 + (4 + (5 + 0))))
空參數(shù)包
空參數(shù)包就是參數(shù)包中不含任何參數(shù)。對于大多數(shù)操作符,空參數(shù)包將會引發(fā)編譯錯(cuò)誤。對于 && 或 ||,空參數(shù)包是合法的,其中 && 的展開結(jié)果為 true,||的展開結(jié)果為 false。在逗號 , 操作符中,空參數(shù)包也合法,展開為 void()。
例 4: 計(jì)算指定區(qū)間內(nèi)包含指定數(shù)值的個(gè)數(shù)
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: 檢查插入多個(gè)元素是否成功
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 時(shí)出錯(cuò), 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
到此這篇關(guān)于C++17中的折疊表達(dá)式實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++17 折疊表達(dá)式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VS2019配置OpenCV時(shí)找不到Microsoft.Cpp.x64.user的解決方法
這篇文章主要介紹了VS2019配置OpenCV時(shí)找不到Microsoft.Cpp.x64.user的解決方法,需要的朋友可以參考下2020-02-02
C++實(shí)現(xiàn)旋轉(zhuǎn)掃描儀的示例代碼
旋轉(zhuǎn)掃描儀(Rotating?Scanner),也稱為旋轉(zhuǎn)掃描儀或圓形掃描儀,是一種用于獲取圖像和文檔的設(shè)備,下面就跟隨小編一起來學(xué)習(xí)一下如何使用C++實(shí)現(xiàn)旋轉(zhuǎn)掃描儀功能吧2024-02-02
C++使用鏈表實(shí)現(xiàn)圖書管理系統(tǒng)
這篇文章主要介紹了C++使用鏈表實(shí)現(xiàn)圖書管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
直觀理解C語言中指向一位數(shù)組與二維數(shù)組的指針
這篇文章主要介紹了直觀理解C語言中指向一位數(shù)組與二維數(shù)組的指針,數(shù)組指針是C語言入門學(xué)習(xí)過程中的重點(diǎn)和難點(diǎn),需要的朋友可以參考下2016-05-05
C++ 中的new 和 delete 運(yùn)算符及new和malloc的區(qū)別解析
在C++中,又引出了一個(gè)新玩法:new 和 delete,在C++中,new是用來動(dòng)態(tài)開辟內(nèi)存的,delete是用來釋放我們所動(dòng)態(tài)開辟的內(nèi)存C++中的new和delete運(yùn)算符及new和malloc的區(qū)別解析,感興趣的朋友跟隨小編一起看看吧2024-11-11

