標籤:

如何評價 C++14 ?


謝謝邀請。我先發個大牛會議後的感想鏈接吧:The View from the C++ Standard meeting September 2013 Part 1 (C/C++ Cafe)

======================2014年2月26日更新============================

最近在準備畢業論文,所以現在有空來更新回答這個問題。

正如 @vczh所說,這幾個是比較大的。

我與同事一起閱讀探討過幾個提案,我把我負責的幾個說一下吧,沒有負責的就談一個。

第一個是Return type deduction for normal functions,參考鏈接是:Return type deduction for normal functions

這一個提案其實在C++11的時候就提到了,但是由於當時投票的時候時間已經不夠了,這個提案也就順延了。這個提案的意義是加強了auto,如在函數上,可以不像11那樣,需要一個Trailing Return Type了。

舉個例子吧

在11中,你需要這樣:

auto f(int a, int b) -&> decltype( a + b )
{
int i = a + b;
return i;
}
int main()
{
std::cout &<&< f(1,2) &<&< std::endl; return 0; }

然而在這個提案中,你就可以這樣了

auto f(int a, int b)
{
int i = a + b;
return i;
}
int main()
{
std::cout &<&< f(1,2) &<&< std::endl; return 0; }

也就是說,可以不要那個「尾巴」了。

而且在這個提案中,auto也可以用在模板中了,具體可以看提案。

而對於這個提案,我們只在一個地方有疑問:

auto sum(int i) {
if (i == 1)
return i; // return type deduced to int
else
return sum(i-1)+i; // ok to call it now
}

這裡,的確是這樣的。但是我們當時提出了一個疑問,如果我這裡的return statement是這樣的

auto sum(int i) {
if (i == 1)
return i; // return type deduced to int
else
return sum(i-1)+i + 0.0; // 這樣怎麼辦呢?
}

可能會說自動提升,但是這裡的提案說應該deduce to int,是根據這裡的i來判定的,但是我這裡加了0.0後,一切就變了。這一個當時我們給了C++標準委員會的Michael Wong,不過很遺憾,我後面走了,不知道答覆是什麼。

另外一個是:Heterogeneous lookup in associative containers。 鏈接是:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3465.pdf

這是一個有關Library的改進,是一個如果你沒有熟悉STL,絕對想不到竟然沒有的東西,因為我在拿到這個提案的時候,潛意識就是覺得以前竟然沒有?

簡單的來說,由於map等關聯容器的內部數據結構和vector這樣的不一樣,所以你可以發現find等,在map中你是有對應的map成員函數來保證的,因為是平衡樹的查找,可以保證是log級別的複雜度。在這篇提案前,有一個函數方法叫equal_range,而對於這個查找匹配元素,以前的map等關聯容器只接受一個Key,而沒有自定義的比較函數。那麼如果沒有內置的operator &< 支持的話,你就只能使用std::equal_range來做了,但是很顯然這個複雜度比log級別的要高,所以這篇提案就建議為關聯容器的equal_range加上自定義比較函數的參數了,而自定義比較函數需要滿足的條件是:strict weak orderings。這個就是那什麼if ( x &< y ) { return true;} if ( y &< x ) {return false;}那一套,這個請參考C++標準庫那本書相關的介紹,肯定有這個說明。

這裡面,還有一個提案是:make_unique。鏈接是:ISO/IEC JTC1/SC22/WG21
N3656

順便推薦一下,我原來經常看這篇提案的作者,來自微軟的Stephan T. Lavavej,在Channel 9的一套很不錯的關於STL的視頻,我受益匪淺。這篇提案沒有多少好說的了,C++11沒有加進去,又是讓人覺得匪夷所思,我們有了std::shared_ptr和std::make_shared,那麼有了std::unique_ptr,為什麼沒有make_unique呢?

我負責看以及與同事分享的還有一篇提案:關於字元串Literal的值的。鏈接為:http://www.open-std.org/JTC1/sc22/WG21/docs/papers/2013/n3642.pdf 這篇提案沒有特殊之處,主要是可以加入ms, s等東西,而對於這篇提案,我曾經提過一個反饋意見,為什麼不更加精確到皮秒,這對於一些科學研究來說,是需要這麼精確的。

最後說一篇不是我負責的,但是引起了我們激烈討論的一篇提案:放鬆constexpr的限定。鏈接為:Relaxing constraints on constexpr functions

這篇提案可謂是深得標準委員會人員的心,不可否認,這篇提案對於普通開發人員無疑是福音,因為可以再次提高性能。但是對於編譯器開發人員簡直是噩夢的一篇提案。說實話,在C++11的所有特性中,constexpr絕對是一個很難實現的特性,我不能透露ibm編譯器如何實現的,感興趣的可以去參看GCC或者Clang的實現。直到現在,Visual C++的實現constexpr都是Partial的狀態。眾所周至,constexpr有一些限定,比如只能返回一條語句等,即使這樣,編譯器做起來都是很頭痛的一件事情。這篇提案簡直逆天了,要去掉這些條件,還可以加入if,for什麼的了,,具體的可以參看提案內容。我只能說簡直喪心病狂,完全不管編譯器開發者的死活。當時我們激烈討論了到底怎麼實現的,但是也沒有討論出來什麼。但就是這篇提案,標準委員會舉雙手雙腳贊成,而且還說有實現的先例:D語言。我也不知道該說什麼了。

其餘還有一些比如泛型Lambda等,我這裡就沒有提了,因為我沒有看這些提案,我就不說了。

最後總結一下就是,C++14可以稱為更加完美的C++11,這是我的觀點。我覺得這些提案本就應該在C++11出現,但是卻由於各種因素才拖到C++14中了。 C++的確變得更加複雜了,但是對於今天學習C++的人來說是更幸福的,少了很多奇淫技巧,多了更多照顧開發者的東西。

======================2015年7月15日更新==============================

似乎這個一年前寫的答案又被翻出來了,然後我就補一下去年留下的那個疑問的回復。

auto sum(int i) {
if (i == 1)
return i; // return type deduced to int
else
return sum(i-1)+i + 0.0; // 這樣怎麼辦呢?
}

對於這個,是不允許的,編譯器會報錯,不會類型轉換。


對比C++11,C++14改變比較大的有

Concept-lite

模板lambda表達式

函數返回decltype(auto)

第一個是給寫庫用的那些對模板不熟悉的可以直接跳過,對於熟悉模板的人來說,Concept-lite對於用戶唯一的好處估計就是錯誤信息比較容易看懂了。因為只是lite,所以其實沒太大用處。

模板lambda表達式可以讓你少寫巨長無比的類型,decltype(auto)也是

=====================================

看了 @藍色 貼的文章,我覺得C++永遠的跟正則表達式構造的詞法分析器說拜拜了,連詞法分析也只能跟語法分析和語義分析一起做了,好蛋疼……


整體來說,除了Concept Lite外,C++14是C++11的補丁。Concept Lite是整個模板系統的補丁。

-----------------

關於constexpr, 233333, 沒有指針的時候還好說,給你來點指針,基本上就跪了。理論上constexpr的極限是:但凡每次運行都固定的東西那就一定能推斷的出來。


熟習使用C++11的人看到C++14都會欣喜若狂,但是壓根連C++本身都沒太搞明白的,估計看到C++14都是一個反映:這什麼玩意,關我啥事。使用其他腳本語言的看到C++14會想,C++再怎麼學習我們腳本也做不到我們腳本這樣好,反而把自己搞的巨複雜,一門越來越臃腫的語言。

好吧,我是全棧,主攻C++。首先你得承認C++11是好的改進,我才能繼續誇14,否則14就沒有了存在的基礎。比如你用nghttp2的C++庫,Lambda的使用會讓你非常銷魂,asio可能得使用很長時間才能感覺到lambda的好,但是到應用層級,你在使用lambda做回調的時候就知道他能多大程度的有益於工程。11讓我們能夠傳lambda(在11出來之前我就有使用boost的lambda,11出來後我也使用golang的coroutine,都是一個道理),但是傳的時候我就發現我不能捕獲一個之前沒有定義的常量,而我是有這個需求的,因為非同步調用的產生的位置點本身就是一個變數。

還有可以文本的二進位,還可以』分隔,對於我們這種底層程序員簡直是福音有木有。但是關聯容器的異構查找還有元編程的改進,雖然不關我啥事,我也用不到,就像吃瓜群眾一樣,不知道你們在搞啥。但是我知道寫庫的人會因此收益。

還有auto的出現,我感覺是C++11中我使用最多的特性,然而返回值,你在設計一個系統架構的時候,有沒有遇到過我擦我實在是不想返回一個長長的map&&>::iterator定義,真心累啊,有木有。你還不能對它typedef,因為那就更噁心了。C++14的返回值auto我覺得是一個更大的改進,雖然用的情況不多,但是在用到的時候真心想親一口。

成員變數初始化,反正C++11的成員變數初始化對我的生活的改善巨大,但是就是union不能初始化,搞到我都不想用union了,C++14又說可以用了,您說說,我能不開心麽?

至於optional我就是吃瓜群眾了。返回bool我感覺挺好的,optional我也要檢查,我寧肯變數是隨即值也不希望變數為空。可能有人會喜歡?我想不出來,但是多年的經驗告訴我,這通常是因為我知識不夠,經驗不足。


我個人觀點:C++14主要是對lambda的補全和標準庫易用性的改進。

關於lambda舉幾個例子:

在C++11中:

std::shared_ptr& x = std::make_shared(1);
auto f = [x] { std::cout &<&< (*x) &<&< std::endl; } // OK std::unique_ptr& y (new X);
auto g = [y] { std::cout &<&< (*y) &<&< std::endl; } // Error: std::unique_ptr is not copyable auto h = [y] { std::cout &<&< (*y) &<&< std::endl; } // OK auto i = [y] {...} // syntax error auto j = [z = std::move(y)] { } // syntax error

用簡單的話來說明:C++11的lambda捕捉類對象時,要麼調用複製構造函數,要麼通過引用,而不管通過什麼手段,都不能讓lambda在捕捉類對象時調用其轉移構造函數。而且通過引用來捕捉上下文變數並不總是有效,比如下面這個例子:

std::function& g(int x)
{
std::unique_ptr& p = new int(x);
return [p] { return (*p)++; };
}
auto x = g(1);
x(); // Undefined behaviour

這一點導致std::unique_ptr的在非同步操作時的實用性大打折扣,如果我們需要讓用作非同步回調的lambda函數捕捉一個智能指針,我們只能使用std::shared_ptr。在C++14中,引入了 Lambda captures expressions,解決了這個問題

std::function& g(int x)
{
std::unique_ptr& p = new int(x);
return [p = std::move(p)] { return (*p)++; }; // OK in c++14
// [ ]
}
auto x = g(1);
std:;cout &<&< x() &<&< std::endl; // prints 1 std:;cout &<&< x() &<&< std::endl; // prints 2 ......

除此之外,C++14也改進了STL的易用性,例如std::less&的改進:

template& struct less; // C++98
template& struct less; //Since C++14
template& struct less {
bool operator &< (const T lhs, const T rhs) { return lhs &< rhs; } }; //Since C++14 template&<&> struct less& {
template&
bool operator &< (const L lhs, const R rhs) { return lhs &< rhs; } }; auto a = less&<&>();
a(1.2f, 0); //OK
auto b = less&();
b(1.2f, 0); // Should cause compile error

在C++14中,對於std::less,std::greater等對void進行了特化,不光少敲了幾個字,還更通用了。


C++98/03: Traditional C++

C++11/14: Modern C++

Modern C++就是為了「新手友好」開發出來的新語言

用smart pointer換掉raw pointer

用container換掉內置數組

向動態類型語言學習auto, decltype

以上的改進使得Modern C++在面向類的編程範式裡邊無限向Java靠攏

只用STL和primitive type(不含raw pointer raw array)拷貝控制可以全部使用合成實現,比Traditional C++不知道高到哪裡去了

不過貌似現在也沒有人寫純粹的Modern C++教程 兩個世代的東西混雜起來講確實就比較複雜了


哎,我特么連11都沒看完,這就到14了?!


C++的入門門檻越來越高,心智負擔越來越重,越來越不適合新手,而一門不能吸引新手的語言是沒有未來的。在我看來,C++標準委員會最應該做的事情不是在語言特性上搞花樣,而是應該大力增強應用開發庫/框架,避免大家一遍一遍的造輪子。這麼多年來,C++標準委員會在這方面幾乎無所作為。


個人認為規則越繁雜的語言越垃圾,就如同windows系統一樣不斷更新補丁遮蓋之前設計的不足,C++語法不如C簡潔,又沒有java等易用,兩面都不討好,我覺得當下最好是提供易用的標準庫,如同xcode,eclipse像樣的ide,還有操作系統直接大力支持,eclipse雖然支持c++但還是用c++自己實現環境比較好,本人一直感慨win下c++沒找到如同java canvas一樣好用的圖形api


推薦閱讀:

【for(int i=10, j=1; i=j=0; i++, j--)()】將循環幾次?
無編程基礎,跳過C直接學C++,壞處是學習難度陡峭,還是會有知識缺陷,還是二者都有?
關於《深度探索C++對象模型》有一段話看不懂?
輪子哥可以分享一下曾經是怎樣帶學生的嗎?
cout 和 cin 的底層實現是怎樣的?

TAG:C |