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);
}
留言