C++ Has Become More Pythonic
译自:http://preshing.com/20141202/cpp-has-become-more-pythonic
近些年C++ 发生了很多变化。最新的两个版本,C++11
和 C++14
引入了如此多的新特性,正如Bjarne Stroustrup
所说的:“它感觉就像一门新的语言”。
确实是这样。现代C++形成了一种全新的编程风格——使我不得不注意到它带有的更多Python
的味道。基范围的for
循环、类型推导、vector和map的初始化、lambda表达式。随着你更深入的探索现代C++,你越会发现Python的痕迹在里面。
现代C++直接受Python的影响吗?或者仅仅是Python在C++之前使用了这些设计?由你来判断。
Literals
Python在2008年引入了二进制字面值。现在C++14
拥有了它们。
1 | static const int primes = 0b10100000100010100010100010101100; |
Python早在1998年引入了原始字符串字面值,它们在硬编码正则表达式或Windows路径时很方便。C++11
使用略微不同的语法加入了同样的想法:
1 | const char* path = R"(c:\this\string\has\backslashes)"; |
Range-Based For Loops
在Python中,for
循环总是在一个Python对象上迭代:
1 | for x in myList: |
与此同时,将近30年,C++只支持C风格的for
循环。最终,在C++11
中,基于范围的for
循环被添加:
1 | for (int x : myList) |
Auto
Python一直是一种动态类型语言。任何地方,你都不用声明变量的类型,因为类型是对象自己的属性。
1 | x = "Hello world!" |
另一方面,C++不是动态类型的,它是静态类型语言。但是从C++11
使用`auto’关键字进行类型推导以来,你能够看起来像动态类型一样来编写代码:
1 | auto x = "Hello world!"; |
当你调用那些被好几种类型重载的函数,例如std::ostream::operator<<
,或模板函数的时候,C++就更表现出动态类型语言的特征。C++14
更进一步扩充了对auto
关键字的支持,增加了对auto
返回值和
lambda函数使用auto
参数的支持。
Tuples
Python几乎从开始就支持tuple
。当你需要把几个值打包在一起的时候表现的非常友好,而不需要命名一个类。
1 | triple = (5,6,7) |
C++在C++11
中把tuple
添加到了标准库中。在这一提议中甚至提到是从Python中得到的灵感:
1 | auto triple = std::make_tuple(5,6,7); |
Python可以让你解包一个tuple
到分开的变量中:
1 | x,y,z = triple |
你在C++中使用std::tie
也可以做到同样的事情:
1 | std::tie(x,y,z) = triple; |
Uniform Initialization
在Python中,list
是一个内建类型。这样,你可以使用单一的表达式来创建一个Python列表:
1 | myList = [6,3,7,8] |
C++中的std::vetcor
是Python列表的最相近的模仿。在C++11
中新添加了统一初始化,现在也可以让我们使用单一的表达式来创建它们:
1 | auto myList = std::vector<int>{6,3,7,8}; |
在Python中,你也可以使用单一的表达式创建一个字典:
1 | myDict = {5: "foo", 6: "bar"}; |
同样的,统一初始化也可以工作在C++的std::map
和unordered_map
:
1 | auto myDict = std::unordered_map<int, const char*>{{5, "foo"}, {6, "bar"}}; |
Lambda Expressions
自从1994年开始Python就支持了lambda函数:
1 | myList.sort(key = lambda x: abs(x)) |
lambda表达式在C++11
中被添加:
1 | std::sort(myList.begin(), myList.end(), [](int x, int y){return std::abs(x) < std::abs(y);}); |
在2001年,Python增加了静态嵌套作用域,它可以使得lambda函数捕获在外围函数中定义的变量:
1 | def adder(amount): |
同样的,C++的lambda表达式支持一套灵活的捕获规则,使你能够做到相似的事情:
1 | auto adder(int amount) { |
Standard Algorithms
Python的内建filter
函数使你从列表有选择性的拷贝元素(但推荐使用列表推导):
1 | result = filter(lambda x: x >= 0, myList) |
C++11
引入了std::copy_if,它使我们可以使用相似的,几乎是函数式的风格:
1 | auto result = std::vector<int>{}; |
其它C++算法借鉴了Python内建的transform
,any_of
,all_of
,min
和max
函数。即将到来的rangs提议将更进一步的简化这些表达式。
Parameter Packs
Python在1998年开始支持任意参数列表。你可以定义一个函数,它可以接受可变数量的参数。这些参数表现为一个tuple
,当把它们传给另一个
函数时tuple
会被展开:
1 | def foo(*args): |
C++11
添加了对参数包的支持。不同于C风格的可变参数,它和Python的任意参数列表很像,参数包有一个名字来代表整个参数序列。一个重要的区别在于:C++的参数包在运行时并不表现为一个单一的对象。你只有通过模板元编程技术在在编译时来操纵它们。
1 | template <typename... T> auto foo(T&&... args) { |
并非所有C++11
和C++14
的新特性都借鉴于Python,但其中很大一部分看起来似乎如此。Python被认为是一个友好的、平易近人的编程语言,或许它的一些魅力已经开始暗淡了?
你觉得如何?C++的这些新特性是否使C++变得更简单、更平易近人或者更富有表达力呢?