看板 C_and_CPP 關於我們 聯絡資訊
本文大部份內容來自此網頁: C++ Has Become More Pythonic http://preshing.com/20141202/cpp-has-become-more-pythonic/ --------------------------- 我以前也是覺得C++的語法看起來很複雜很討厭的人。 不過C++這幾年變了很多,C++11 和 C++14 加了很多新語法進去。 連C++的老爸 Bjarne Stroustrup http://www.stroustrup.com/C++11FAQ.html#think 都說: “It feels like a new language.” 該怎麼說呢?語法上愈來愈簡潔,愈來愈python化了... 不知道是python影響C++還是C++影響python? 以下就大致列出python跟C++的共同點。 ### 語法 (Literals) ### Python從2008年開始引進字面輸入二進位值(binary literals)。 gcc從2007年就支援(雖然C standard從來沒把這個加進去)。 C++是直到C++14 http://en.cppreference.com/w/cpp/language/integer_literal 才正式支援: static const int primes = 0b1010000010001010001010; 當字串中有**'\\'**的時候,以前你可能得這樣寫: const char* path = "(c:\\this\\string\\has\\backslashes)"; C++11 http://en.cppreference.com/w/cpp/language/string_literal 開始可以字面輸入原始字串(raw string literals)。 const char* path = R"(c:\this\string\has\backslashes)"; Python則是1998年就支援了。 ### 有範圍根據的 for 迴圈(Range-Based For Loops) ### Python裡要在同一個物件裡用迴圈把其中元素一一取出的話很簡單: for x in myList: print(x) 古早的C++寫起來很累贅 // array for (int i=0; i<10; ++i) std::cout<< A[i] << ' '; // vector(我討厭這種寫法...) for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) { /* std::cout << *it; ... */ } http://en.cppreference.com/w/cpp/language/range-for C++11開始你就能優雅地寫for loop: std::vector<int> v = {0, 1, 2, 3, 4, 5}; for(const int &i : v) // access by const reference std::cout << i << ' '; std::cout << '\n'; for(auto i: v) // access by value, the type of i is int std::cout << i << ' '; std::cout << '\n'; for(auto&& i: v) // access by reference, the type of i is int& std::cout << i << ' '; std::cout << '\n'; for(int n: {0, 1, 2, 3, 4, 5}) // the initializer may be a braced-init-list std::cout << n << ' '; std::cout << '\n'; int a[] = {0, 1, 2, 3, 4, 5}; for(int n: a) // the initializer may be an array std::cout << n << ' '; std::cout << '\n'; for(int n: a) std::cout << 1 << ' '; // the loop variable need not be used std::cout << '\n'; ### 自動指定型別 Auto ### Python有個方便的地方就是不用理會變數到底該用怎樣的型別(data type), 會自動幫你決定或改變。 C++以前可不是這樣,但是C++11 http://en.cppreference.com/w/cpp/language/auto 開始多了自動推斷類型的語法: auto x = "Hello world!"; std::cout << x; 就算是有函式重載(function overloading)的情況下, 呼叫函式時編譯器也會對於auto自動判別的型別指到相對應的函式去。 C++14更方便,連自動決定函式的回傳型別(Function return type deduction) https://en.wikipedia.org/wiki/C%2B%2B14#Function_return_type_deduction 都能辦到了。 auto Correct(int i) { if (i == 1) return i; // return type deduced as int else return Correct(i-1)+i; // ok to call it now } auto Wrong(int i) { if (i != 1) return Wrong(i-1)+i; // Too soon to call this. No prior return statement. else return i; // return type deduced as int } ### Tuples ### Python很久就有tuple這個能把不同型別的變數包在一起又不能修改的型別。 triple = (5, 6, 7) print(triple[0]) C++11開始也有了,甚至直接挑明這是跟Python致敬。 auto triple = std::make_tuple(5, 6, 7); std::cout << std::get<0>(triple); Python可以把tuple拆開 x, y, z = triple C++11當然也可以 std::tie(x, y, z) = triple; ### 統一初始化 (Uniform Initialization) ### Python可以當初始一個List類型時就把元素加進去,之後想增加也行。 Dictionary也可以這樣搞。 myList = [6, 3, 7, 8] myList.append(5); myDict = {5: "foo", 6: "bar"} print(myDict[5]) C++11 http://www.stroustrup.com/C++11FAQ.html#init-list 開始, vector、std::map 和 unordered_map也可以這樣搞了 auto myList = std::vector<int>{ 6, 3, 7, 8 }; myList.push_back(5); auto myDict = std::unordered_map<int, const char*>{ { 5, "foo" }, { 6, "bar" } }; std::cout << myDict[5]; ### Lambda 表達式 (Lambda Expressions) ### Python的Lambda是很神奇的東西... myList.sort(key = lambda x: abs(x)) C++11 http://www.stroustrup.com/C++11FAQ.html#lambda 居然也有了... (可我還是比較喜歡函式指標阿....) std::sort(myList.begin(), myList.end(), [](int x, int y){ return std::abs(x) < std::abs(y); }); ### Standard Algorithms ### Python可以用內建的filter函式把符合條件的元素複製出來... result = filter(lambda x: x >= 0, myList) C++11 http://en.cppreference.com/w/cpp/algorithm/copy 的 std::copy_if有著相似的功能... (怎麼突然有種好神奇的感覺?) auto result = std::vector<int>{}; std::copy_if(myList.begin(), myList.end(), std::back_inserter(result), [](int x){ return x >= 0; }); ### Parameter Packs ### Python這個功能我還真沒用過,實際用法可以參考這裡 http://hangar.runway7.net/python/packing-unpacking-arguments def func1(x, y, z): print x print y print z def func2(*args): # Convert args tuple to a list so we can modify it args = list(args) args[0] = 'Hello' args[1] = 'awesome' func1(*args) func2('Goodbye', 'cruel', 'world!') # Will print # > Hello # > awesome # > world! C++11 也能這樣做 http://www.stroustrup.com/C++11FAQ.html#variadic-templates template <typename... T> auto foo(T&&... args) { return std::make_tuple(args...); } ... auto triple = foo(5, 6, 7); 看到這裡,是不是覺得C++變得愈來愈優雅了? -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 90.41.1.211 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1462301210.A.9FC.html ※ 編輯: wtchen (90.41.1.211), 05/04/2016 02:56:44
james732: 推 05/04 09:26
Frozenmouse: 說到 param pack,昨天好奇去看了C++17 的 fold expr 05/04 10:06
Frozenmouse: 覺得這語法超神奇的XDDD 05/04 10:06
Frozenmouse: C++在這幾年真的是不斷進化,都快不認識了 05/04 10:07
Neisseria: 建議板大連結不要放括號裡,會帶到瀏覽器,造成錯誤 05/04 10:28
拿掉了,因為本來是用kramdown寫的。
prismwu: 這篇不錯耶 05/04 10:44
exeex: 推 for 對 vector的用法太實用了 05/04 10:51
bibo9901: 老實說你講的這幾點都不是python獨有/獨創 05/04 11:28
uranusjr: 沒人說這些是 Python 獨有/創新, 但 Python 是極少數擁 05/04 14:11
uranusjr: 有「全部」的語言 -- 現在 C++ 也加入這個榮譽俱樂部了 05/04 14:11
uranusjr: 希望 C++ 未來也能有 enhanced proposal 機制 05/04 14:13
uranusjr: (打錯, 是 enhancement proposal) 05/04 14:13
freeunixer: lambda 是從 fp 來的,最早在 lisp 就已經有了. 05/04 14:33
freeunixer: Java 是從 8 開始才有,但基本上現在的 Python, 05/04 14:33
freeunixer: 對 lambda 依賴已經沒有以前高,用型別運算產生式就行. 05/04 14:34
freeunixer: 另外,以前蔡學鏞推過一個 rebol.不過這幾年沒啥進步.. 05/04 14:38
freeunixer: 如果對 C++ 難分難捨,那也許也可以留意一下 Rust 05/04 14:39
※ 編輯: wtchen (90.41.1.211), 05/04/2016 15:27:43
wtchen: 有大大可以寫篇Rust跟C++的比較文嗎?保證不砍 05/04 15:37
bibo9901: 說得也是 05/04 15:58
CoNsTaR: 推 Rust 05/04 15:59
freeunixer: Parameter Packs 其實就是未指定參數名稱,就都算它的. 05/04 16:25
freeunixer: 比如 x= ,y= , a,b,c ,沒有 = 指定輸入值,就全給 *arg 05/04 16:26
freeunixer: 所以 func1 把 arg 前兩個換掉再丟進 func2 去配對. 05/04 16:31
freeunixer: 2 1 05/04 16:32
freeunixer: 一般看到的範例是 func1(x, *args) 這種型式. 05/04 16:34
freeunixer: 沒被指定參數名稱抓到的,就全送進 *arg 05/04 16:34
wtchen: C++11之後,C跟C++的分歧就越來越大了.... 05/04 16:36
bibo9901: 其實可以更徹底一點XD 為了兼容C實在犧牲太大了.. 05/04 16:38
freeunixer: python 3.x 還有 **args 抓進去直接配成 dict 的 k:v 05/04 16:43
Frozenmouse: 與C相容…前朝遺毒 (誤 05/04 17:16
Bencrie: 應該說...歷史包袱(? 05/04 21:38
tuyutd0505: 推 有些寫法第一次看到 學習了 05/04 21:56
laba5566: 推 05/04 22:43
fanntone: C++11之後就是突破大氣層的感覺 05/04 23:45
loveflames: final跟override也不錯 05/05 00:11
loveflames: variadic template搭配多重繼承也蠻有趣的 05/05 00:17
shaopin: for(auto&& i: v) // access by reference, the type of 05/05 04:38
shaopin: 對這個有點問題, 如果auto&& 是by reference 那auto&呢? 05/05 04:38
red0210: 推 寫得很棒 05/05 07:18
loveflames: auto&&產生ref,auto&產生左值ref 05/05 07:53
x000032001: 偷推yoco大神的文章 #19gioP8j 05/05 10:51
Sylveon: 大推~ 05/05 12:01
CoNsTaR: auto&&產生型態為右值ref的左值ref 05/05 12:07
CoNsTaR: auto&參考到一個左值 不產生新物件 05/05 12:08
Caesar08: auto &是l value ref,auto &&是r value ref 05/05 12:22
loveflames: 不對,auto&&不是專門用在rvalue ref 05/05 12:33
loveflames: 其中有用到跟template一樣的折疊規則 05/05 12:34
Caesar08: 對不起,我錯了。有具名的&&才是r value ref。auto &&是 05/05 12:45
Caesar08: forwarding reference 05/05 12:45
Caesar08: 簡單來說,auto &&i:v要看v是l value還是r value。如果 05/05 12:47
Caesar08: v是l value,那auto &&i就是int &i;如果 05/05 12:47
Caesar08: v是r value,那auto &&i就是int &&i 05/05 12:48
shaopin: 請問什麼是有具名的&&? 05/05 16:02
Caesar08: 應該說,有具型態的才對。例如直接指定int &&,此時已經 05/05 16:09
Caesar08: 指定型態是int,而不是用auto幫你進行type deduction 05/05 16:10
loveflames: 注意const auto&&不適用折疊規則,此時就是rvalue ref 05/05 16:36
loveflames: 跟template的推導規則一樣 05/05 16:36
CoNsTaR: 簡單的說,reference to rvalue 本身也是一個 lvalue 05/05 17:46
suhorng: auto 跟重載那段有點怪, 這兩個沒關聯吧 05/05 19:01
suhorng: Python lambda 的語法限制有點詭異. Python 不太推lambda 05/05 19:03
wtchen: 我自己是不太喜歡用lambda,太簡化的東西反而反應不過來 05/05 19:04
suhorng: parameter pack 跟 variadic template 很不同吧? 05/05 19:05
Caesar08: A template with at least one parameter pack is 05/05 19:19
Caesar08: called a variadic template. 05/05 19:19
loveflames: STL如果沒lambda,functor寫起來會很痛苦 05/05 19:45
ronin728: Python也只是跟別人學來的,C++剛好學到一樣的部分而已z 05/06 11:17
ronin728: 這些特性早在Ada,ML,Scheme就有了,他們都比Python老=.= 05/06 11:23
Frozenmouse: 現代程式語言不都互相影響嗎,真要考古誰原創考不完w 05/06 16:30
os653: 只求好寫、好偵錯、速度快又不用造輪子,誰抄誰不重要 05/06 19:34
ho83leo: 推整理 05/07 22:39
eye5002003: 好文!匿名函式這招實在太好用 05/07 22:41
rodion: 推... 希望C++17把平行化也好好的弄出來:> 05/08 01:46
fr3ak: 跟 Python 背景的朋友聊天講到 C++ Templates 的時候, 常以 05/16 02:53
fr3ak: compile-time dock-type 類比 05/16 02:53