作者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://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1462301210.A.9FC.html
※ 编辑: wtchen (90.41.1.211), 05/04/2016 02:56:44
1F:推 james732: 推 05/04 09:26
2F:推 Frozenmouse: 说到 param pack,昨天好奇去看了C++17 的 fold expr 05/04 10:06
3F:→ Frozenmouse: 觉得这语法超神奇的XDDD 05/04 10:06
4F:→ Frozenmouse: C++在这几年真的是不断进化,都快不认识了 05/04 10:07
5F:→ Neisseria: 建议板大连结不要放括号里,会带到浏览器,造成错误 05/04 10:28
拿掉了,因为本来是用kramdown写的。
6F:推 prismwu: 这篇不错耶 05/04 10:44
7F:推 exeex: 推 for 对 vector的用法太实用了 05/04 10:51
8F:→ bibo9901: 老实说你讲的这几点都不是python独有/独创 05/04 11:28
9F:→ uranusjr: 没人说这些是 Python 独有/创新, 但 Python 是极少数拥 05/04 14:11
10F:→ uranusjr: 有「全部」的语言 -- 现在 C++ 也加入这个荣誉俱乐部了 05/04 14:11
11F:→ uranusjr: 希望 C++ 未来也能有 enhanced proposal 机制 05/04 14:13
12F:→ uranusjr: (打错, 是 enhancement proposal) 05/04 14:13
13F:→ freeunixer: lambda 是从 fp 来的,最早在 lisp 就已经有了. 05/04 14:33
14F:→ freeunixer: Java 是从 8 开始才有,但基本上现在的 Python, 05/04 14:33
15F:→ freeunixer: 对 lambda 依赖已经没有以前高,用型别运算产生式就行. 05/04 14:34
16F:→ freeunixer: 另外,以前蔡学镛推过一个 rebol.不过这几年没啥进步.. 05/04 14:38
17F:→ freeunixer: 如果对 C++ 难分难舍,那也许也可以留意一下 Rust 05/04 14:39
※ 编辑: wtchen (90.41.1.211), 05/04/2016 15:27:43
18F:→ wtchen: 有大大可以写篇Rust跟C++的比较文吗?保证不砍 05/04 15:37
19F:推 bibo9901: 说得也是 05/04 15:58
20F:推 CoNsTaR: 推 Rust 05/04 15:59
21F:→ freeunixer: Parameter Packs 其实就是未指定参数名称,就都算它的. 05/04 16:25
22F:→ freeunixer: 比如 x= ,y= , a,b,c ,没有 = 指定输入值,就全给 *arg 05/04 16:26
23F:→ freeunixer: 所以 func1 把 arg 前两个换掉再丢进 func2 去配对. 05/04 16:31
24F:→ freeunixer: 2 1 05/04 16:32
25F:→ freeunixer: 一般看到的范例是 func1(x, *args) 这种型式. 05/04 16:34
26F:→ freeunixer: 没被指定参数名称抓到的,就全送进 *arg 05/04 16:34
27F:→ wtchen: C++11之後,C跟C++的分歧就越来越大了.... 05/04 16:36
28F:→ bibo9901: 其实可以更彻底一点XD 为了兼容C实在牺牲太大了.. 05/04 16:38
29F:→ freeunixer: python 3.x 还有 **args 抓进去直接配成 dict 的 k:v 05/04 16:43
30F:推 Frozenmouse: 与C相容…前朝遗毒 (误 05/04 17:16
31F:推 Bencrie: 应该说...历史包袱(? 05/04 21:38
32F:推 tuyutd0505: 推 有些写法第一次看到 学习了 05/04 21:56
33F:推 laba5566: 推 05/04 22:43
34F:推 fanntone: C++11之後就是突破大气层的感觉 05/04 23:45
35F:推 loveflames: final跟override也不错 05/05 00:11
36F:推 loveflames: variadic template搭配多重继承也蛮有趣的 05/05 00:17
37F:推 shaopin: for(auto&& i: v) // access by reference, the type of 05/05 04:38
38F:→ shaopin: 对这个有点问题, 如果auto&& 是by reference 那auto&呢? 05/05 04:38
39F:推 red0210: 推 写得很棒 05/05 07:18
40F:推 loveflames: auto&&产生ref,auto&产生左值ref 05/05 07:53
41F:→ x000032001: 偷推yoco大神的文章 #19gioP8j 05/05 10:51
42F:推 Sylveon: 大推~ 05/05 12:01
43F:推 CoNsTaR: auto&&产生型态为右值ref的左值ref 05/05 12:07
44F:→ CoNsTaR: auto&参考到一个左值 不产生新物件 05/05 12:08
45F:→ Caesar08: auto &是l value ref,auto &&是r value ref 05/05 12:22
46F:推 loveflames: 不对,auto&&不是专门用在rvalue ref 05/05 12:33
47F:→ loveflames: 其中有用到跟template一样的折叠规则 05/05 12:34
48F:→ Caesar08: 对不起,我错了。有具名的&&才是r value ref。auto &&是 05/05 12:45
49F:→ Caesar08: forwarding reference 05/05 12:45
50F:→ Caesar08: 简单来说,auto &&i:v要看v是l value还是r value。如果 05/05 12:47
51F:→ Caesar08: v是l value,那auto &&i就是int &i;如果 05/05 12:47
52F:→ Caesar08: v是r value,那auto &&i就是int &&i 05/05 12:48
53F:推 shaopin: 请问什麽是有具名的&&? 05/05 16:02
54F:→ Caesar08: 应该说,有具型态的才对。例如直接指定int &&,此时已经 05/05 16:09
55F:→ Caesar08: 指定型态是int,而不是用auto帮你进行type deduction 05/05 16:10
56F:推 loveflames: 注意const auto&&不适用折叠规则,此时就是rvalue ref 05/05 16:36
57F:→ loveflames: 跟template的推导规则一样 05/05 16:36
58F:推 CoNsTaR: 简单的说,reference to rvalue 本身也是一个 lvalue 05/05 17:46
59F:推 suhorng: auto 跟重载那段有点怪, 这两个没关联吧 05/05 19:01
60F:→ suhorng: Python lambda 的语法限制有点诡异. Python 不太推lambda 05/05 19:03
61F:→ wtchen: 我自己是不太喜欢用lambda,太简化的东西反而反应不过来 05/05 19:04
62F:→ suhorng: parameter pack 跟 variadic template 很不同吧? 05/05 19:05
63F:→ Caesar08: A template with at least one parameter pack is 05/05 19:19
64F:→ Caesar08: called a variadic template. 05/05 19:19
65F:推 loveflames: STL如果没lambda,functor写起来会很痛苦 05/05 19:45
66F:推 ronin728: Python也只是跟别人学来的,C++刚好学到一样的部分而已z 05/06 11:17
67F:→ ronin728: 这些特性早在Ada,ML,Scheme就有了,他们都比Python老=.= 05/06 11:23
68F:推 Frozenmouse: 现代程式语言不都互相影响吗,真要考古谁原创考不完w 05/06 16:30
69F:推 os653: 只求好写、好侦错、速度快又不用造轮子,谁抄谁不重要 05/06 19:34
70F:推 ho83leo: 推整理 05/07 22:39
71F:推 eye5002003: 好文!匿名函式这招实在太好用 05/07 22:41
72F:推 rodion: 推... 希望C++17把平行化也好好的弄出来:> 05/08 01:46
73F:推 fr3ak: 跟 Python 背景的朋友聊天讲到 C++ Templates 的时候, 常以 05/16 02:53
74F:→ fr3ak: compile-time dock-type 类比 05/16 02:53