溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

折疊表達式如何在C++中實現(xiàn)

發(fā)布時間:2020-11-19 15:28:19 來源:億速云 閱讀:196 作者:Leah 欄目:開發(fā)技術

今天就跟大家聊聊有關折疊表達式如何在C++中實現(xiàn),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據(jù)這篇文章可以有所收獲。

C++11 提供了可變模板參數(shù)包, 使函數(shù)可以接受任意數(shù)量的參數(shù). 但在 C++11中展開參數(shù)包稍顯麻煩, 而 C++17 的折疊表達式使得展開參數(shù)包變得容易, 其基本語法是使用 (…) 的語法形式進行展開。

支持的操作符

C++17中,折疊表達式支持 32 個操作符:

 +, -, *, /, %, ^, &, |, =, <,
>, <<, >>, +=, -=, *=, /=, %=, ^=, &=, |=, <<=,
>>=,==, !=, <=, >=, &&, ||, ,, .*, ->*.

折疊分類

折疊位置

1.左折疊
2.右折疊

操作數(shù)個數(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的結果

例 2: 右折疊

template <typename ... Ts>
auto sum(Ts ... ts)
{
  return (ts + ...);
}

例 1 中, 參數(shù)包 … 位于操作符的左側,故爾稱為左折疊。 如果 …位于操作符右側,則稱為右折疊,如例 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)生編譯錯誤,如

int the_sum {sum()};
/*大致的錯誤輸出如下

In instantiation of 'auto sum(Ts ...) [with Ts = {}]':
error: fold of empty expansion over operator+
   return (... + ts);
*/

若要解決空參數(shù)包的編譯錯誤,針對例 1,可以加上一個數(shù)值 0,可以解決編譯錯誤又可以使得語義不變,這個 0 相當于缺省值。通過加上一個數(shù)值,折疊就變成了二元折疊,如例 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))))

空參數(shù)包

空參數(shù)包就是參數(shù)包中不含任何參數(shù)。對于大多數(shù)操作符,空參數(shù)包將會引發(fā)編譯錯誤。對于 && 或 ||,空參數(shù)包是合法的,其中 && 的展開結果為 true,||的展開結果為 false。在逗號 , 操作符中,空參數(shù)包也合法,展開為 void()。

例 4: 計算指定區(qū)間內包含指定數(shù)值的個數(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: 檢查插入多個元素是否成功

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++中實現(xiàn)有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI