C++ 逐漸 Python 化
近幾年C++有了很多變化。最新的兩個版本C++11和C++14,引入了如此多的新特性,用 Bjarne Stroustrup的話說就是“感覺就像一個新語言一樣。”
真的。現代c++形成了一個全新的編程風格,我不能不注意到它帶有更多的Python味道。基于范圍(Range)的循環、類型推導、向量、map初始化和lambda表達式。你越是探索現代C++,你越能夠發現它里面的Python痕跡。
是Python直接影響了現代C++嗎?還是在C++傳開前,Python已經采用了一些有用的結構?由你自己判斷。
字面值
Python在2008年引入二進制字面值。現在C++14也有了。【更新:Thiago Macieira在評論中指出,GCC實際上早在2007年就已經支持了。】
static const int primes = 0b10100000100010100010100010101100;
Python早在1998年引入了 原始字符串字面值。在硬編碼正則表達式或Windows路徑時很方便。 C++11也添加了同樣的特性,只是語法上略有不同:
const char* path = R"(c:\this\string\has\backslashes)";
基于范圍的For循環(Range-Based For Loops)
在Python中,for循環總是迭代遍歷一個Python對象:
for x in myList: print(x)
與此同時,在近30年里。C++僅支持C風格for循環。最后,在C++11中, 基于范圍的for循環被添加進去。
for (int x : myList) std::cout << x;
與Python迭代協議不同,你可以迭代一個 std::vector 或任何實現了begin和end成員函數的類。有了基于范圍的for循環后,我經常發現自己希望C++能內建像Python的xrange函數一樣的函數。
自動化
Python一直以來都是一個動態類型語言。你不需要聲明變量類型,因為類型是對象本身的屬性。
![]()
x = "Hello world!"print(x)
從另一方面來說,C++不是動態類型語言。是靜態類型。不過在C++11中將 auto 關鍵字 改作他用以用于類型推導,你能夠寫 看起來很像動態類型的代碼:

auto x = "Hello world!"; std::cout << x;
當你調用重載幾個類型的函數時,比如 std::ostream::operator<< 或者一個模板函數,C++更像一個動態類型語言。C++14進一步充實以支持auto關鍵字,為auto添加了 返回值支持和lambda函數 參數支持。
元組
Python從一開始就很好的定義了元組類型。當你需要把幾個值整合在一起的時候,元組就非常適合,這樣就再不需要命名類來實現同樣的功能了。
triple = (5, 6, 7) print(triple[0])
C++在C++11標準庫中添加了對元組的支持。C++11的建議書 甚至還提到了這么做是受Python啟發的:
C++
auto triple = std::make_tuple(5, 6, 7); std::cout << std::get<0>(triple);
Pyton允許你把一個元組解析為多個獨立的變量:
x, y, z = triple
在C++里,你可以使用std::tie實現同樣的功能:
C++
std::tie(x, y, z) = triple;
統一的初始化
在Python里,列表是內置類型。因此,你可以只使用一個表達式來創建Python列表:
myList = [6, 3, 7, 8] myList.append(5);
C++的向量(std::vector)與Python的列表最為相似。如今,C++11里新增的 統一的初始化可以讓我們只使用一個表達式來創建向量和列表了:
C++
auto myList = std::vector<int>{ 6, 3, 7, 8 };
myList.push_back(5); 在Python里,你還可以只使用一個表達式來創建一個 字典:
myDict = {5: "foo", 6: "bar"}
print(myDict[5]) 與此類似,統一的初始化也適用于有序映射(std::map)和無序映射(unordered_map):
C++
auto myDict = std::unordered_map<int, const char*>{ { 5, "foo" }, { 6, "bar" } };
std::cout << myDict[5]; Lambda表達式
Python從1994年開始支持lambda函數。

myList.sort(key = lambda x: abs(x))
Lambda表達式是在C++11中被添加進去。
std::sort(myList.begin(), myList.end(), [](int x, int y){ return std::abs(x) < std::abs(y); });
2001年,Python添加了 靜態嵌套作用域,可以讓lambda函數抓取定義在封閉函數內的變量。
def adder(amount): return lambda x: x + amount ... print(adder(5)(5))
同樣,C++ lambda表達式支持一堆靈活的 抓取規則,可以讓你做相似的事情:
auto adder(int amount) { return [=](int x){ return x + amount; };
}
...
std::cout << adder(5)(5);
標準算法
Python內建 filter 函數可以讓你有選擇的從一個列表中拷貝項(雖然列表解析是首先):
result = filter(lambda x: x >= 0, myList)
C++11中 引入了 std::copy_if ,讓你可以使用一個類似的、相當功能的類型:
auto result = std::vector<int>{};
std::copy_if(myList.begin(), myList.end(), std::back_inserter(result), [](int x){ return x >= 0; });
其他的C++ 算法模仿了Python的內建函數包括 transform、 any_of、 all_of, min 以及 max。即將到來的 范圍提案有潛力進一步簡化這些表達式。
參數打包
Python 從 1988 年就開始支持任意長度的參數列表. 你可以定義一個函數接受任意數量的實參,Python 會將他們放到一個元組(tuple)中, 你還可以將這個元組重新展開為一個實參列表,并把他們傳遞進另一個函數:
def foo(*args): return tuple(*args) ... triple = foo(5, 6, 7)
C++11 引入了對 參數包(parameter packs) 的支持. 它類似于 Python 的任意長度參數列表,而不同于 C 風格的可變參數列表, 這個參數包有自己的標識符來表示整個實參序列。關鍵區別在于:在 C++ 中,這個參數包不能在運行時做為一個單獨的對象來操作。你只能通過模板元編程技術在編譯時來操縱他們。
template <typename... T> auto foo(T&&... args) {
return std::make_tuple(args...);
}
...auto triple = foo(5, 6, 7);
并非所有的 C++ 11 和 14 中的特性都借鑒于 Python。只是其中很大一部分特性看似如此。 Python 被認為是一種對使用者親近友好的編程語言。隨著時間的推移以及這些特性逐漸被其他語言借鑒,它其中一些特質也逐漸暗淡下來。
你怎么看呢?C++ 中的這些新特性會不會使 C++ 更加簡單,親和,更具表現力呢?
本文地址:http://www.oschina.net/translate/cpp-has-become-more-pythonic
原文地址:http://preshing.com/20141202/cpp-has-become-more-pythonic/