作者wtchen (沒有存在感的人)
看板C_and_CPP
標題[分享] C++和Python的相似處
時間Wed May 4 02:46:48 2016
本文大部份內容來自此網頁:
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