accumulate第三個三處所傳的儲值的型別必須定義了 「+」運算子,例如:將空串當作乙個字面值傳給第三個引數是不可以的
//會導致編譯錯誤,const char*上並沒有定義"+"運算子
string
sum= accumulate(v.cbegin(), v.cend(), "");
//string上定義了"+"運算子
string
sum= accumulate(v.cbegin(), v.cend(), string(""));
只接受乙個單一迭代器來表示第二個序列的演算法,都假設第二個序列至少與第乙個序列一樣長;
back_inserter是一種向容器中新增元素的迭代器,當我們通過此迭代器賦值時,賦值運算子會呼叫push_back;
vector
vec; //建立乙個空vector
fill_n(back_inserter(vec), 10, 0); //新增10個元素到vec
關於lambda表示式:
(1)表示乙個可呼叫的**單元,可以將其理解為乙個未命名(編譯器會給它命名)的內聯函式;其實是乙個函式物件,[ ] 稱為lambda introducer,取用外部的變數要放在[ ]中;
auto f = ;
f(); // prints "hello lambda"
(2)可能定義在函式內部,必須使用尾置返回,不能有預設引數,可以直接使用定義在當前函式之外的名字,例如cout;
(3)可以忽略引數列表和返回型別,但必須永遠包含捕獲列表和函式體;
(4)可以傳值或者傳引用,要修改傳進來的資料必須在()後宣告 mutable;**獲的值是在建立時拷貝,而不是呼叫時拷貝;
(5)可以在lamada函式體內部像其他函式一樣定義static變數等等;
(6)可以使用隱式捕獲,但不推薦;
(7)當定義乙個lambda時,編譯器生成乙個與lambda對應的新的(未命名的類型別),使用auto定義乙個用lambda初始化的變數時,定義了乙個從lambda生成的型別的物件;
(8)lambda主要應用於原來我們傳給標準庫的一些函式的自定義引數時,比如sort函式,現在我們可以改用lambda表示式來自定義我們的比較函式,表達更方便;原來我們傳遞給標準庫有些函式(比如find_if)的任何函式都只能接受乙個引數,現在我們可以使用lambda來解決這個問題
int id = 0;
//由於是傳值,內部改變不會影響外部,並且對應於(4),**獲的值是在建立時拷貝,不是呼叫時拷貝
auto f = [id]()mutable ;
id = 42;
f(); f(); f(); //id:0 id:1 id:2
/*該lambda表示式可以類似為下面的class,但還有一些差別*/
class functor
};functor f;
佔位符,形式為_n,n表示第幾個引數;定義在名為placeholders的命名空間中,這個命名空間本身又定義在std中; using namespace std::placeholders; placeholders空間定義在functional標頭檔案中
可以將bind函式看做乙個通用的函式介面卡,可以使用佔位符對原函式重新包裝
(1)重排引數順序
//g是是乙個有兩個引數的可呼叫物件
auto g = bind(f, a, b, _2, c, _1);
//生成乙個新的可呼叫物件g,g的第一各引數被傳遞給f作為最後乙個引數,g的第二個引數被傳遞給f當做第三個引數
// 呼叫g(x, y); 相當於呼叫 f(a, b, y, c, x);
(2)繫結引用引數
//有些繫結的引數我們希望以引用方式傳遞,或者時要繫結的引數的型別無法拷貝(例如:ostream型別)
// bind只會拷貝傳給它的引數,如果我們希望傳遞給bind乙個物件又不拷貝它,就必須使用標準庫ref函式
for_each(words.begin(), words.end(),
bind()print, ref(os), _1, ' '));
流迭代器
(1)istream_iterator
// 從cin讀取int,一直到eof,將輸入的值用來構造vec
istream_iterator in_iter(cin), eof;
vector
vec(in_iter, eof);
// 也可以使用演算法來操作流迭代器,計算輸入的int型數字的和
cout
<< accumulate(in_iter, eof, 0) << endl;
(2)ostream_iterator
//使用ostream_iterator來輸出值的序列,每個元素輸出後還列印出乙個空格(也可以是其他字串,但必須是c風格的)
ostream_iterator out_iter(cout, " ");
for (auto e : vec)
*out_iter++ = e; //賦值語句實際上將元素寫到cout
cout << endl;
// 運算子*和++實際上對ostream_iterator物件那個不做任何事情,但是還是推薦這種寫法
//呼叫copy來列印vec中的元素,比迴圈更加簡單
copy(vec.begin(), vec.end(), out_iter);
cout << endl;
可以呼叫reverse_iterator的base成員來將乙個反向迭代器轉換成其對應的普通迭代器(即正向)
迭代器總共有5種,從下往上分別為繼承關係
(1)input iterator;
(2)output iterator;
(3)forward iterator;
(4)bidirectional iterator;
(5)random-access iterator;
//練習10.30
istream_iterator in_iter(cin), eof;
vector
vec(in_iter, eof);
sort(vec.begin(), vec.end());
ostream_iterator out_iter(cout, " ");
copy(vec.begin(), vec.end(), out_iter);
/*消除重複單詞,並統計長度大於sz的單詞數量*/
#include
#include
#include
#include
using
namespace
std;
void elimdups(vector
&words)
bool isshorter(const
string &s1, const
string &s2)
//根據ctr的數值來判斷返回單詞的單數還是複數形式
string make_plural(size_t ctr, const
string &word,
const
string &ending)
void biggies(vector
&words,
vector
::size_type sz)
); //獲取乙個迭代器,指向第乙個滿足size() >= sz 的元素
auto wc = find_if(words.begin(), words.end(),
[sz](const
string &a)
);//計算元素數目
auto count = words.end() - wc;
/* //直接呼叫count_if,獲得滿足size()>= sz的元素個數
auto count = count_if(words.begin(), words.end(),
[sz](const string &a)
);*/
cout
<< count << " "
<< make_plural(count, "word", "s")
<< " of length "
<< sz << " or longer "
<< endl;
for_each(wc, words.end(),
(const
string &s) );
cout
<< endl;
}int main()
; biggies(words, 5);
return
0;}
c primer 第十章泛型演算法lambda
謂詞是乙個呼叫表示式,其返回結果是乙個能用做條件的值。標準庫演算法為此分為兩類 1 一元謂詞 意味著只能接受單一引數 2 二元謂詞 意味著他們有兩個引數 接受謂詞的演算法對輸入序列中的元素呼叫謂詞。因此元素型別必須能轉換為謂詞的引數型別。以sort和isshorter舉例 eg bool issho...
c Primer 第十章 泛型演算法 重點梗概
演算法依賴於迭代器,而迭代器不依賴於容器,所以演算法不依賴於容器 但是演算法往往涉及比較,但是容器中的元素不一定定義了比較運算子,所以 大多數的演算法提供了一種方法,允許我們使用自定義的操作來代替預設的運算子 對於只讀取而不改變元素的演算法,最好使用cbegin cend 這裡要注意的是謂詞的種類,...
第十章 泛型演算法
特殊迭代器 插入迭代器 被繫結到乙個容器上,可用來向容器插入元素 流迭代器 被繫結到輸入 輸出流上,可用來遍歷所關聯io流 反向迭代器 向後而不是向前移動,除了forward list,容器都擁有它 移動迭代器 不是拷貝其中的元素,而是移動它們 插入迭代器操作 it t 在it指定的當前位置插入t,...