謂詞是乙個呼叫表示式,其返回結果是乙個能用做條件的值。
標準庫演算法為此分為兩類:
1、一元謂詞(意味著只能接受單一引數)
2、二元謂詞(意味著他們有兩個引數)
接受謂詞的演算法對輸入序列中的元素呼叫謂詞。因此元素型別必須能轉換為謂詞的引數型別。
以sort和isshorter舉例
eg:
bool
isshorter
(const string &s1,
const string &s2)
sort
(word.
begin()
, words.
end(
), isshorter)
;
問題背景:根據演算法接受一元謂詞還是二元謂詞,我們傳遞給演算法的為此必須嚴格接受乙個或兩個引數,當我們想用find_if判斷乙個string長度是否大於乙個給定長度,我們需要傳入乙個string::size_type sz的引數,以及string,但是find_if只接受一元謂詞,為了解決這個問題,我們引入lambda表示式。
介紹lambda:乙個lambda表示式表示乙個可呼叫的**單元。我們可以理解為乙個未命名的內聯函式。其包括乙個返回型別,乙個引數列表和乙個函式體。
[capture list]
(parameter list)
->
return type
//基本形式
//可以忽略引數列表和返回型別,但當我們想制定返回型別時,必須使用該形式中所用的尾置返回
1、捕獲列表:
使用函式中定義的區域性變數,且必須是那些明確指定的變數。
捕獲方式分為三種:值捕獲、引用捕獲、隱式捕獲。
首先是值捕獲:
採用值捕獲的前提是變數可以拷貝。與引數不同,**獲的變數的值實在lambda建立時拷貝,而不是呼叫時拷貝:
void
fcn1()
; v1 =0;
auto j =f(
);//j為42,f儲存了我們建立時的拷貝
}
接著介紹引用捕獲:
乙個以引用方式捕獲的變數與其他任何引用行為類似。這裡只談問題和限制。如果我們引用捕獲了乙個變數,就必須確保被引用的物件在lambda執行的時候是存在的。
由於lambda捕獲的都是區域性變數,加入lambda在函式結束後執行,則其捕獲的變數已經不存在了。
引用捕獲有時候是必要的,比如在接受乙個流引數時候,因為流無法拷貝,只能採取引用的策略。
void
fcn2()
; v1 =0;
auto j =f(
);//j為0,f儲存的是引用而不是拷貝
}
使用注意:
盡量保持lambda的變數捕獲簡單化。確保lambda每次執行的時候這些資訊都有與其意義是程式設計師的責任。
一般來說我們應該儘量減少捕獲的資料量,來避免捕獲導致的潛在的問題。同時,如果可能的話我們應該盡量避免捕獲指標和引用。
最後介紹隱式捕獲:
除了顯示的列出我們希望使用的變數外,我們還可以讓編譯器根據lambda體中的**來推斷我們要使用的哪些變數。為了指示編譯器推斷捕獲列表,應在捕獲列表中寫乙個&或=。&告訴編譯器採用引用捕獲的方式,=表示採用值捕獲方式。
wc =
find_if
(words.
begin()
, words.
end(),
[=](
const string &s)
);
也可以混用隱式捕獲和顯示捕獲,當我們混用時候捕獲列表的第乙個元素必須是乙個&或=,同時第二個元素必須與第乙個元素型別不同。
for_each
(words.
begin()
, words.
end(),
[=,&os]
(const string &s)
);
2、可變lambda
預設情況下對於乙個值拷貝的變數lambda不改變其值,但當我們想改變時候需要在引數列表首加上關鍵字mutable。因此可便lambda能省略引數列表。
void
fcn3()
; v1 =0;
auto j =f(
);//j為43
}
引用捕獲變數是否可以修改依賴於此引用指向的是乙個const型別,還是乙個非const型別:
void
fcn4()
; v1 =0;
auto j =f(
);//j為1
}
3、指定lambda返回型別
預設情況下,如果乙個lambda體包含return之外的任何語句,則編譯器假定此lambda返回void。
因此當我們寫如下語句時會報錯
transform
(vi.
begin()
, vi.
end(
), vi.
begin()
,(int i)
);
所以此時我們需要使用尾置返回型別
transform
(vi.
begin()
, vi.
end(
), vi.
begin()
,(int i)
->
int)
;
4、向lambda傳遞引數
與普通函式不同,lambda不能有預設引數,因此lambda呼叫的實參數目與形引數目相等。
//isshorter
(const string &a,
const string &b)
c primer 筆記,第十章(泛型演算法)
accumulate第三個三處所傳的儲值的型別必須定義了 運算子,例如 將空串當作乙個字面值傳給第三個引數是不可以的 會導致編譯錯誤,const char 上並沒有定義 運算子 string sum accumulate v.cbegin v.cend string上定義了 運算子 string s...
第十章 泛型演算法
特殊迭代器 插入迭代器 被繫結到乙個容器上,可用來向容器插入元素 流迭代器 被繫結到輸入 輸出流上,可用來遍歷所關聯io流 反向迭代器 向後而不是向前移動,除了forward list,容器都擁有它 移動迭代器 不是拷貝其中的元素,而是移動它們 插入迭代器操作 it t 在it指定的當前位置插入t,...
c Primer 第十章 泛型演算法 重點梗概
演算法依賴於迭代器,而迭代器不依賴於容器,所以演算法不依賴於容器 但是演算法往往涉及比較,但是容器中的元素不一定定義了比較運算子,所以 大多數的演算法提供了一種方法,允許我們使用自定義的操作來代替預設的運算子 對於只讀取而不改變元素的演算法,最好使用cbegin cend 這裡要注意的是謂詞的種類,...