C++自修入門實境秀、C++ Primer 5版研讀秀 62/ ~ v10 泛用演算法(generic algorithms)10.3.2. ...





Calling find_if

find_if演算法會回傳一個找到的元素的迭代器,若沒找到則回傳find_if第2個引數(即迭代器範圍的末後位置的迭代器)



頁391

The for_each Algorithm

for_each演算法

13:00演算法(algorithm)這個單字的動詞可以用call、use

14:00

可見前面學的predicate,就是或者說必須帶入一種可呼叫物件(callable object)

for_each 的引數有一個可呼叫物件(callable object)

尾端回傳(trailing return)型別是和「->」箭號運算子(arrow operator:-> operator)一起的(頁229)

[capture list] (parameter list) -> return type { function body }

所以沒有回傳型別,就沒有箭號運算子



for_each(wc, words.end(),

[](const string &s){cout << s << " ";});

cout << endl;



22:30

for_each這個可呼叫物件的引數,卻不是predicate判斷式,而是呼叫後可以執行什麼工作的。是述句(statement),不是條件式或判斷式(predicate)



The capture list in this lambda is empty, yet the body uses two names: its own parameter, named s , and cout . The capture list is empty, because we use the capture list only for (non static ) variables defined in the surrounding function. A lambda can use names that are defined outside the function in which the lambda appears. In this case, cout is not a name defined locally in biggies; that name is defined in the iostream header. So long as the iostream header is included in the scope in which biggies appears, our lambda can use cout .

捕捉串列(capture list)只有在是非靜態的成員上才有必要使用。因為靜態成員是不依函式式結束就無效的、生命週期就結束的。

只要是具名mame的東西,都是所謂的識別項(identifier)

捕捉串列僅用於區域性的非static變數;lambda可以直接使用區域性的static 以及定義在該函式外的變數。

在函式外的就不是區域的,而是public的了。

Putting It All Together

全部整合起來

void biggies(vector<string> &words,

vector<string>::size_type sz){

elimDups(words); // put words in alphabetical order and remove duplicates

// sort words by size, but maintain alphabetical order for words of the same size

stable_sort(words.begin(), words.end(),//sort 預設必是由小到大排序…

[](const string &a, const string &b)

{ return a.size() < b.size();});//…所以須配合著<小於運算子來用!也就是說sort是藉由「<」小於運算子比較的結果來決定由小到大排序的順序的

//要明白這些predicate(p.386)是怎麼作用的,才能真正弄懂

// get an iterator to the first element whose size() is >= sz

auto wc = find_if(words.begin(), words.end(),

[sz](const string &a)

{ return a.size() >= sz; });//可見find_if是用「true」來判斷predicate。且只找第一個符合條件(predicate為true)的

// compute the number of elements with size >= sz

auto count = words.end() - wc;

cout << count << " " << make_plural(count, "word", "s")

<< " of length " << sz << " or longer" << endl;

// print words of the given size or longer, each one followed by a space

for_each(wc, words.end(),

[](const string &s){cout << s << " ";});

cout << endl;

}

1:2:43

頁392

練習10.14

練習寫labmda表達式

#include <iostream>

using namespace std;

int main() {

auto lmbda = [](const int& i1, const int& i2) ->int{return i1 + i2; };//指定asign型別須用auto,不能用int

cout << lmbda(1,13) <<endl;//不管有沒有參數,一定不能省掉呼叫運算子(call operator)

}

因為lambda是可呼叫物件(callable object),呼叫運算子當然不能省略

練習10.15

1:17:40

#include <iostream>

using namespace std;

int main() {

int i2=3;

auto lmbda = [i2](const int& i1) ->int{return i1 + i2; };//指定asign型別須用auto,不能用int

// 'i2' cannot be implicitly captured because no default capture mode has been specified

//C++ an enclosing-function local variable cannot be referenced in a lambda body unless it is in the capture list

cout << lmbda(1) <<endl;//不管有沒有參數,一定不能省掉呼叫運算子(call operator)

}



練習10.16

1:29:30

#include <iostream>

#include <string>

#include <vector>

#include <algorithm>

using namespace std;

void biggies(vector<string>& vecStr,vector<string>::size_type sz ) {

//因為要對vecStr做編輯(sort演算法都會動到容器元素),所以不能是對常值的參考:

//const vector<string>& vecStr

sort(vecStr.begin(), vecStr.end());

stable_sort(vecStr.begin(), vecStr.end()

, [](const string& s1, const string & s2) {return s1.size()<s2.size();});

auto iterB = find_if_not(vecStr.cbegin()

, vecStr.cend(), [sz](const string& s) {return s.size()<sz; });

for_each(iterB, vecStr.cend(), [](const string& s) {cout << s << endl; });

}

int main() {

vector<string> vec;

string word;

while (cin>>word)

{

vec.push_back(word);

}

biggies(vec,8);

}



練習10.17

見Sales_data.cpp或Sales_data.cpp即可。

練習10.12

Severity Code Description Project File

Error C2678 binary '=': no operator found which takes a left-hand operand of type 'const Sales_data' (or there is no acceptable conversion)因為非const可以轉成const,但低階的const反向的轉換並不存在(頁162) prog1 C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\algorithm

失敗,俟考(已上GitHub)

5:34:00

第62集 2:23:00

void sortIsbn(vector<Sales_data>& vecSales_data)

{//因為sort會對vecStr做編輯、會動到容器元素,所以不能是對常值的參考:const vector<Sales_data>&

sort(vecSales_data.begin(), vecSales_data.end(),

[](const Sales_data& sd1, const Sales_data& sd2)

{return sd1.isbn().size() < sd2.isbn().size(); });

//stable_sort(vecSales_data.begin(), vecSales_data.end(), compareIsbn);

}

以上問題解決,但仍有錯誤。俟考!

Severity Code Description Project File Line Suppression State

Error LNK2019 unresolved external symbol "void __cdecl sortIsbn(class std::vector<struct Sales_data,class std::allocator<struct Sales_data> > const &)" (?sortIsbn@@YAXAEBV?$vector@USales_data@@V?$allocator@USales_data@@@std@@@std@@@Z) referenced in function main這個問題就出在函式的宣告和定義是不同調的(在const上),所以才「unresolved external symbol」無法解析

prog1 V:\Programming\C++\oscarsun72\prog1\prog1\prog1.obj 1

Error LNK1120 1 unresolved externals prog1 V:\Programming\C++\oscarsun72\prog1\x64\Debug\prog1.exe 1

解決了,原來就在const &上面。若寫成void sortIsbn(vector<Sales_data>const& vecSales_data)

但加入sort後又回到前面的錯誤,二者衝突也。 第62集 3:17:00

真的是解決了!關鍵在於不能不必寫成另一個函式,而是直接執行sort演算法。然而這樣就不能讓Sales_data有它自己的排序方法(介面)了,所以一樣可以改寫成一個介面函式

這次的問題當在const使用上出現衝突故!第62集 4:14:00所以一定要追蹤const的使用,務必求其一致且無衝突!4:36:00以上錯誤,真的都是const問題!

sort是必定要改變原容器的元素,唯不增減元素而已,所以決定不能用對const的參考,只能用plain reference。(可用「plain reference」全文檢索)

run:

#include<vector>

#include<string>

#include"Sales_data.h"

#include <iostream>

using namespace std;

void printVectorSales_data(const std::vector<Sales_data>& vecSale_data)

{

for (Sales_data s : vecSale_data)

{

print(cout, s); cout << endl;

}

}

int main() {

Sales_data sd;

vector<Sales_data>vecSale_data;

while (read(cin, sd))

{

vecSale_data.push_back(sd);

}

sortIsbnDescending(vecSale_data);

printVectorSales_data(vecSale_data);

cout << endl;

sortIsbnAscending(vecSale_data);

printVectorSales_data(vecSale_data);

}

Sales_data.h

……

//定義Sales_data自己的排序:

bool compareIsbnLength(const Sales_data& ,const Sales_data &);

void sortIsbnAscending( vector<Sales_data>&);

void sortIsbnDescending( vector<Sales_data>&);

void printVectorSales_data(const std::vector<Sales_data>& vecSale_data);

#endif // !SALES_DATA_H

Sales_data.cpp

……

#include<algorithm>

……

bool compareIsbnLength(const Sales_data& sd1, const Sales_data& sd2)

{

return sd1.isbn().size() < sd2.isbn().size();

//return sd1.bookNo.size() < sd2.bookNo.size();//二式皆可,因為目前Sales_data為struct,預設其成員存取權為公開

}



void sortIsbnAscending(vector<Sales_data>&vecSales_data)

{

sort(vecSales_data.begin(), vecSales_data.end(), compareIsbnLength);

stable_sort(vecSales_data.begin(), vecSales_data.end(),

[](const Sales_data& sd1, const Sales_data& sd2)->bool {

return sd1.isbn() < sd2.isbn(); });//再用string的小於運算子作比較

//用<即遞增,小的排前面,用>即遞減,大的排前面

////第2階用售出數量來排序:這樣寫變成全部改用售出數量來排序了

//stable_sort(vecSales_data.begin(), vecSales_data.end(),

// [](const Sales_data& sd1, const Sales_data& sd2)->bool {

// return sd1.soldQ < sd2.soldQ; });

}



void sortIsbnDescending( vector<Sales_data> & vecSales_data)

{

sort(vecSales_data.begin(), vecSales_data.end(),compareIsbnLength);

stable_sort(vecSales_data.begin(), vecSales_data.end(),

[](const Sales_data& sd1, const Sales_data& sd2)->bool {

return sd1.isbn() > sd2.isbn(); });//用string型別的比較//使用lambda

////第2階用售出數量來排序:這樣寫變成全部改用售出數量來排序了

//stable_sort(vecSales_data.begin(), vecSales_data.end(),

// [](const Sales_data& sd1, const Sales_data& sd2)->bool {

// return sd1.soldQ>sd2.soldQ; });

}

全檔詳見:

https://github.com/oscarsun72/prog1-C-Primer-5th-Edition-s-Exercises/tree/exercise10_12



4:51:00

4:54:50

練習10.18

#include <iostream>

#include <string>

#include <vector>

#include <algorithm>

using namespace std;

void biggies(vector<string>& vecStr,vector<string>::size_type sz ) {

auto iterE=partition(vecStr.begin(), vecStr.end(),//先分組再排序。若先排序再分組則會亂序

[sz](const string& s)->bool {return s.size()>=sz; });

sort(vecStr.begin(), iterE);

stable_sort(vecStr.begin(), iterE

, [](const string& s1, const string& s2) {return s1.size() < s2.size(); });

for_each( vecStr.begin(), iterE, [](const string& s) {cout << s << endl; });

}

int main() {

vector<string> vec;

string word;

while (cin>>word)

{

vec.push_back(word);

}

biggies(vec,8);

}

5:19:55

練習10.19

Rewrite the previous exercise to use stable_partition,which like stable_sort maintains the original element order in the paritioned sequence.

paritioned→partitioned

#include <iostream>

#include <string>

#include <vector>

#include <algorithm>

using namespace std;

void biggies(vector<string>& vecStr,vector<string>::size_type sz ) {

sort(vecStr.begin(), vecStr.end());

stable_sort(vecStr.begin(), vecStr.end(),

[](const string& s1, const string& s2) {return s1.size() < s2.size(); });

auto iterE = stable_partition(vecStr.begin(), vecStr.end(),//分組時不會動到原來的排序

[sz](const string& s)->bool {return s.size() >= sz; });

for_each( vecStr.begin(), iterE, [](const string& s) {cout << s << endl; });

}

int main() {

vector<string> vec;

string word;

while (cin>>word)

{

vec.push_back(word);

}

biggies(vec,8);

}

留言

熱門文章