作者poyenc (髮箍)
看板C_and_CPP
標題Re: 關於 stl 和 c++ 的一點問題
時間Fri Nov 30 01:31:54 2018
哈囉, 如果你對 STL 有興趣的話可以參考下面的影片
(依序看):
CppCon 2018: Jonathan Boccara “105 STL Algorithms in Less
Than an Hour”
https://youtu.be/2olsGf6JIkU
Stephan T. Lavavej - Standard Template Library (STL)
https://bit.ly/2fS8u8c
Stephan T Lavavej - Advanced STL
https://bit.ly/2fS5lFF
其實 STL 粗略來分有
Algorithm 以及
Container 兩部分, 使用
Container 不只需要有部分資料結構的基礎, 也要知道 concept
這個觀念, 知道在 template 裡有對參數型別依賴哪些操作之後,
就可以進一步學習使用
Algorithm.
Algorithm 架構在兩個基本
concept 之上
(當然其他還有很多):
1.
iterator
2.
range
iterator (迭代器) 是類指標物件, 用來指向容器裡的物件, 你可
以用 operator++ 讓迭代器指向容器裡下個物件(概念上), 而不用
在意容器實際上是由什麼資料結構實作而來.
range 這個概念最簡
單的描述就是:
有一個物件集合, 可以用
兩個迭代器去描述, 其中一個
開
始迭代器指向集合中的第一個物件, 另一個
結束迭代器則
用來指向最後一個物件
的後方. 你可以
將開始迭代器不斷
地疊加, 直到它指向結束迭代器為止, 如此就完成尋訪集
合裡的所有物件. 以數學表示大概是 [first, last)這樣
的半開區間
(容器也會提供這樣成對的迭代器)
近年來 C++ Community 也在提倡多使用
Algorithm 來取代重複的
程式碼, 一方面可以提升可讀性, 另一方面也省去不必要的物件定
義. 以簡單的數偶數來說, 你可能會這樣寫:
1 std::array<
int, 5> values{1, 2, 3, 4, 5};
2
3
unsigned even = 0u;
// what type should I use?
4
for (
auto v : values) {
5
if (v % 2 == 0) {
// core logic #1: operate on evens
6 ++even;
// core logic #2: count things
7 }
// #1 + #2: count evens
8 }
9
// 'even' finally available now
你會發現我們在第 3 行定義了 even 變數, 但是要到第 9 行它的
值才是有意義的, 然後必須將迴圈一層層分解看到第 6 行才能知
道它在作什麼, 這邊可以用 std::count_if() 來改寫:
1
auto const even = std::count_if(
2 std::begin(values), std::end(values),
3 [] (
auto v) {
return v % 2 == 0; }
4 );
讀作: count from begin of values to end of
values if v % 2 == 0
然後在 C++20 你可以進一步簡化
(或是用 Boost.Range):
1
auto const even = std::ranges::count_if(
2 values, [] (
auto v) {
return v % 2 == 0; }
3 );
讀作: count all values if v % 2 == 0
使用 lambda 不僅可以清楚表達核心邏輯, 讀碼也可以較快切入重
點
參考資料:
Working Draft (N4789)
http://eel.is/c++draft/alg.count
The One Ranges Proposal (P0896R3)
https://bit.ly/2KGsMma
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 123.193.76.85
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1543512718.A.2BE.html
推 eye5002003: 我到現在還是無法習慣這些用法 11/30 13:10
→ uranusjr: 很遺憾的這是時代的趨勢 (C++ 以外的語言也有類似進化) 11/30 13:31
推 F04E: 您是好人 11/30 15:43
騙騙 P 幣 xD
推 soheadsome: js圈會跟你說這是reactive programming 11/30 19:28
→ descent: 看不懂, 還是覺得第一種寫法好懂 11/30 21:03
→ descent: 而且任何語言用可以用 11/30 21:04
強烈建議搭配 Boost.Range Adaptor, 或是 range-v3 一起服用
range-v3
https://github.com/ericniebler/range-v3
Ranges for the Standard Library (N4128)
https://bit.ly/2P7Zqh7
推 art1: 對最後一種最有感覺,短的程式碼比較容易懂? 11/30 22:55
差別在需要跳多深去 理解/修改 原始碼
推 ilikekotomi: 先推 有空再來看影片 11/30 23:08
推 steve1012: 越長的程式碼越容易出錯 12/01 00:13
推 TitanEric: 感謝分享 12/01 11:54
找個範例來演示:
從大到小印出整數範圍 [1, 100] 中所有 3 的倍數
有 range 及 view 的概念就可以讓程式碼 self-documented, 變
更需求成本就不會很高 (例如改成從小到大印出). 可惜 lambda
的語法偏複雜, 用 Boost.Range, Boost.Phoenix, Boost.Lambda
協作就會簡單很多. 至少我用 for 寫應該會讓人看不懂 xD
auto result = irange(
1,
100 +
1)
| filtered(arg1 %
3 ==
0)
| reversed
;
for_each(result, cout << _1 <<
" ");
連結:
https://ideone.com/Yw3Fap
※ 編輯: poyenc (123.193.76.85), 12/01/2018 15:44:36