C++17 基本完成,對於新特性大家怎麼看?
C++17 Is Near, A Look At The New Features
基本特性在此:tvaneerd/cpp17_in_TTs
把吐槽都看了一遍。基本上,大多數針對單個特性的吐槽,我覺得我從下面的四句話里選一句就可以了:
- 「你不用不代表沒有用」
- 「自己寫個 ○○ 很難嗎」
- 「So?」
- 「時間不夠人手不夠」
只有一條評論我覺得有必要回復一下,那就是
對比一下C++11的更新:auto,lambda,增強的for循環,智能指針。。。都是拿來就用的好東西,一用起來C++立馬變成一門現代語言。再看看C++17,傳說中的的concept,module,range都難產了,反倒是新加了一堆只有語言律師才想去學習的特性。我是做機器學習的,對於我來說,C++17的新特性一個都用不到。
作者:dawnmist
鏈接:https://www.zhihu.com/question/56943731/answer/151578944
來源:知乎
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
這裡提出了兩個批評,IIUC,
- C++17 沒有變得更像一門現代語言;
- 機器學習領域的 C++ 用戶沒有 benefit from C++ 的新特性。
1) 是很嚴重的批評。如果真是如此,說明我們沒有 evolve 這個 language. 下面我用兩個例子說明不是這麼回事。
Structured binding
std::map&
auto [it, inserted] = m.insert_or_assign("key", 42);
一步就可以知道你的 key-value pair 是被插入了還是被更新了還有它的位置,似乎不需要你成為語言律師,並且這是更現代的 C++.
Class template argument deduction
auto v = std::vector{5, 2, 4, 2};
想像腳本語言一樣寫代碼很多年了
2) 也是糟糕的情況。如果一個新興領域的 C++ 用戶整體不能 benefit from C++17 的哪怕是一個特性,那說明這個領域 underrepresented. 但我想對於機器學習,不是這麼回事。
C++17 有至少兩大特性能 potentially 給予機器學習很大幫助,他們加起來給標準新加了約有 50 頁紙:
- Mathematical Special Functions. 這俺不懂,不過如果要自己實現,得雇幾個 PhD.
- Parallel STL.
在講 Parallel STL 之前,我需要導入一個觀念上的轉變。也許過去你們認為只有 libstdc++, libc++ MS STL 這些才算 C++ 標準庫實現,但隨著這些年 C++ 標準庫開始向專門領域擴張,傳統完整標準庫的實現質量會收到這些領域的高水平 vendor 的挑戰,比如,一個只實現了 &
Parallel STL 源於 Nvidia 的 Thrust, 現在已經有 Thrust, SYCL, HPX 等多個實現 (http://www.iwocl.org/wp-content/uploads/iwocl-2015-tutorial-SYCL-part3.pdf),其中的一些已經能同時使用 CUDA/OpenCL, OpenMP, 甚至 MPI 完成 GPU -&> CPU -&> Cluster 的 Heterogeneous computing, 這同時是機器學習的重要方向。
============ 追加 ============
上面給的兩個語言特性的例子看起來並不新鮮?well...
C++17 確實進化出了能在構造抽象方面起到很大作用的東西,但這些地方都不是看一眼就會,需要深入研究。比如我提到的 class template argument deduction, 看上去只是 function template argument deduction 的延伸,但實際上它夾帶的那個特性, deduction guide, 才是 main feature. 問題鏈接里有一個例子:
template &
struct Thingy
{
T t;
};
Thingy(const char *) -&> Thingy& 這真的是在 deduction 嗎?不如說有點無中生有的味道。但如果我給這個特性換個名字,叫 specialization selector, 你就明白了,上面的 Thingy& 本意是允許用戶自己定製 Callback 的類型,結果用戶寫 得到一堆各不相同的 Tasks& 用戶寫上面的代碼時就會選擇到 Tasks& 但要用好 deduction guide, 不但要在頭腦中打破常規,還需要掌握它和 class template argument deduction 的各種規則,不是那種我一貼代碼,別人就能用上的特性。不過我對其在擴展我們 abstraction 方面的前景很有信心,一大波精心設計過的 ClassTemplate(args...) 介面有望到來。
Thingy thing{"A String"}; // &<------- thing.t is a `std::string`.
template &
class Tasks
{
Tasks(Queue q, F on_finished);
};
Tasks(v, []{ cout &<&< ...; });
template &
Tasks(Queue, Fn) -&> Tasks&
我的module呢?!(掀桌)
問我怎麼看嘛,我是這麼看的:不要走C#的老路啊……希望那些不痛不癢的改變全部刪掉,包括但不限於:
- if-init
- structured bindings // 為啥不做徹底一點,優化那個沒人用的tuple有什麼意思,還有這個跟struct的成員聲明順序耦合的功能也是在給大家挖新坑,又可以製造更多的驚喜了
- explicit deduction guides
- fold expressions
- [[fallthrough]] // 這麼多年都成為條件反射了,沒必要
個人覺得很好的特性有:
- constexpr if
- deduction guides
- template&
- single param static_assert // 明明IDE就會幫我跳到代碼里,寫個原因真是多此一舉
- parallel STL // ranges竟然是TS,好氣呀
- nested namespaces
- inline variables
- std::variant // 直接做pattern maching多好,為什麼要發明出這麼多花邊新聞
- std::filesystem // 來晚了,大家的輪子都造好了。現在在標準庫裡面加入對操作系統的封裝的東西,意義已經不大了
- concepts
- coroutines
- networking
- 2d graphics
C++總是在用一種很扭曲的方法實現某一種顯而易見的東西,然後後期又添加一個重複功能的東西來增加易用性
- 比如C++98模板報錯一大片,然後11多了一個扭曲的SFINAE,終於有個Concept來解決了
- 比如tag dispatch,大家寫了那麼多年,編譯器都可以針對性優化了,終於有了個if constexpr
- 比如std::tie,現在發明了個structural binding,這不就是tie的糖嘛,還沒法用std::ignore
- 比如constexpr和const和inline和template說不清道不明的那堆關係
- 比如之前說的ODR,然後大家嫌煩,所以就給const對象和inline function開洞,然後為了寫著爽又發明了個inline variable
- 比如現在有人發明了用顯式指明underlying type的enum class來屏蔽整數隱式轉換,然後修改標準允許這種特殊形式的構造寫法——這不扭曲嗎,用enum來避免隱式轉換???
- 比如之前用operator()來製造函數對象,這還挺正常的,然後後面有了lambda,這很好,然後現在lambda允許捕獲*this了?哈?捕獲*this什麼鬼?
- 比如之前發明了parameter pack,發明了包擴展,大家習慣用swallow函數或者別的什麼東西原地包擴展,把整個包組成一個表達式,然後現在發明了什麼?fold expr?什麼鬼
----繼續吐槽----
- std::any,啥?有move構造函數,但是裡面放的對象依然需要拷貝構造函數?
- std::variant,啥?std::visit怎麼用?要用generic lambda配合constexpr if?我服了,給你們看一片代碼:
std::variant&
std::visit([](auto var/*auto????*/) {
if constexpr (std::is_same_v&
//type is int
} else if constexpr (std::is_same_v&
//type is double
} //.........
}, var);
我這裡大膽預測一下,C++9999的時候會添加一個模式匹配語法用於variant
- std::byte,C++不是號稱提供給你足夠多的抽象,其它的都可以用庫實現嗎,怎麼這個東西就不行了?
光是一個inline variable就讓人想升級了。
已經受夠了在頭文件里extern然後再(隨便)找個cpp文件填定義了。
你們不要黑標準委員會了。你們知道標準委員會有多努力嗎。在剛剛結束的Kona會議上,他們處理了42億個問題。你們看不到,因為你們只關心自己
/s
除了輪子哥的「預言」部分幾乎全部贊同。。。
C++ 14 之後的每次會議前與後的 proposal、trip report 我都翻了非常多遍了,對 17 落得這個下場其實挺失望的。。。
1. structural binding 有了,哦,聽著很好,但是遺憾的是,這貨不支持 */_ wildcard 這種語法,這意味著你要綁定就必須全都綁定。也不支持對每個 binding 做不同的類型控制(例如 [int i , string_view str] = Foo()),也不支持嵌套的。剛開始這個特性語法是 auto { } 但是這樣以後萬一允許把 structural binding 的 auto 換成 concept 就會和 C++ 的大括弧初始化語法衝突:
ForwardIterator {x, y} = std::mismatch(…);
然後有意思的部分來了,auto [] 以後一旦加入嵌套又和 Attribute 的語法衝突!C++ 語法真是爛到無藥可救了啊……然後 Clang 的維護者就說,啊,用 [] 還能好 workaround 點,然後就 [] 了。。。這個特性其實很失敗啊。。C++ 初始化搞那麼多語法,統一的初始化語法只是帶來了更多的坑。。Rust 的 pattern matching 是你怎麼構造的就怎麼解構,C++ 這隻能 gg,搞出這麼個不倫不類的東西。順便一提,這個 proposal 超級快地就進來了,當初 Herb Sutter 還說這個不太可能進 17。。
2. if init,可以讓代碼優雅些,不用為起名字發愁了,沒啥多說的
3. inline variable 明顯又是開始給 C++ 打補丁了。明明加了 module 就好了搞什麼 ODR 什麼 inline function 蛋疼。不過抱怨歸抱怨,這個特性還是不錯的。
4. Fold expr,已經在某個問題里回答過了,垃圾。C++ 的 param pack 太畸形了。
5. template&,恕我直言這個特性就是垃圾。Concept 裡面,auto 是 placeholder,例如 auto x = Foo(); 表明對 x 的類型沒有任何限制,而 Concept 允許 template&
6. deduction guides 這個特性之前有個特別大的問題,就是在 T 那裡,在 Kona 給改了。這個特性挺好的,但是標準庫的支持在 C++ 17 定稿前的非常後期才趕出來,而且只 rev 了 1 次,目測要有坑。
7. constexpr if,我先預警一下,這個東西又要引入新的奇技淫巧了。因為這個東西不允許出現 static_assert(false),所以你需要
template&
struct always_false : std::false_type {};
不過這個特性真的非常非常好用,解決掉一部分 tag dispatch 和 SFINAE。另外,這個理論上可以加快編譯速度,MSVC STL 已經打算在 MSVC 支持 constexpr if 之後全面使用。
8. 表達式那個求值順序。這個特性就是個 sb 啊。。。M$ 的人提的,結果 Windows 上的 ABI 根本沒法完全實現這個。。。無語。
9. guaranteed copy elision ROCKS!!!
C++ 17 改進的最大的還是標準庫
1. std::variant 非常 非常 非常難用,真的,用了就知道了,make_overload 沒有趕上 C++ 17。。。
2. optional/any 不多說
3. string_view:非常有用!但是注意這個不保證以 0 結尾,所以與 OS API 接觸(多數 OS API 要求的字元串都以 0 結尾)時不應該使用 string_view 做介面。哦對了,評論的聚聚提起這個類的 constexpr,再一次體現了 C++ 的垃圾:char_traits&
4. filesystem:很雞肋。。。而且目前據我所知沒有標準庫實現(擺脫 experimental;實現了所有 C++ 17 的要求),Visual C++ 據稱只能在 VS 2019 ship C++ 17 的 filesystem,目前的確是有一個,但是那個實現非常糟糕而且 C++ 17 對於 filesystem 改動已經很大了。但是 VS2017 又要和 VS2015 bin compatible 所以沒法 ship,只能等下一個 major version。我目前用這玩意唯一就是 const path filePath。
5. 並行演算法、數學庫很好,但是根本沒人實現出來現在。。。這個提案的初始版本是 M$ 的人提的,並且給出了一個實現,但是遺憾的是這個人已經離開了 M$,這份實現。。。gg
6. 內存池 委員會終於醒悟了,但是這個還沒有人實現完整的(libc++ 只實現了最基本的)
7. to_chars/from_chars 終於有靠譜的數字字元串轉換了,但是目前沒有標準庫實現
總結:C++ 17 是 library heavy 的。
WG21 的 EWG Chair VV 已經給出了 C++ 20 的規劃,重點是 Module、Concept、Ranges 和 Network。Concept 的語法大改是肯定逃不掉的,Module 目前也有分歧(有人抱怨 GDR 的方案遷移太費勁了,大工程遷移不現實),Ranges 目前情況倒是大好,把 algo 和 iterator 的問題都修了,Network 不感興趣,不感覺會有人用。。。
if-init 好看點而已,雞肋structured bindings 感覺不錯,但用於 struct 時不支持指定成員名字來初始化if constexpr 很有用deduction guides 不錯,但 explicit deduction guides 跟另外單獨寫個函數重載有什麼區別嘛template& 不錯,但沒有 concept 感覺用途受限啊fold expression 只不過是某些情況下寫起來好看點,雞肋nested namespace 稍微有點用single param static assert 這是修了個 bug。。inline variables 也是稍微好看點而已,很雞肋guaranteed copy elision 沒看懂,跟原來有什麼區別嗎?[[fallthrough]] 雞肋[[nodiscard]] 用處不大[[maybe_unused]] 讓編譯器不提示 unused variable 有 N 種方法,不缺這一種string_view 有用optional, vairant, any 有用,然而並沒有 pattern matchingfilesystem 有點用parallel 有用module concept ranges networking 等重要特性全都是 TS
如果下版 Xcode 支持的話,我會用一些 17 的特性。但是如果有人對我說請三年之內不要寫 17-specific code,我也不在意。
相比之下,如果 2005 年的時候有人對我說不能用 C++ 98,或者 2014 年的時候有人說不要用 C++ 11,我都會考慮對項目的方向進行堅決的抵制。
C++ 98 解決了一些基本表達的可能性問題。C++ 11 解決了一些基本表達的標準化問題。相比之下,17 解決的問題沒有那麼迫切。
extern void func(); //declared but never defined
if(1==2)func();
過去gcc上面這段代碼鏈接不會有問題, 而VS上則不行。static_if 終於可以終結這個了,我的模版簡化編程終於可以以比較的可移方植的方式實現了。
加入的一些小的庫和語法還是挺不錯的。
舉幾個例子
std::byte 以前操作單獨的位的時候總是很虛,用char,unsigned char 擔心平台不兼容而且還能用++,--這些操作符。用bitset還太臃腫。用union的話C風格太重。
std::variant 在boost里本人也很喜歡的其中一個組件。以前標準庫里沒有還有很多人用一些手段去支持。
還有if中能定義變數。(算是個語法糖)
boost中實現簡單但是很有用的小東西,還有就是 laguerre expint 這些數學函數也都收錄到C++17中。這些也讓我很滿意。
--------------------------------------------------------------以下是吐槽。----------------------------------------
通用的庫一個都沒加,基本都是讓編譯器越來越魔幻。表示我是寫工程的你搞的那些用不上的東西對我一點用都沒有。
就說網路庫吧不能奢求一個大而全的網路庫,您簡單的給我封裝個套接字成么。(C/C++是我經歷過的唯二的沒有標準網路庫的通用語言)還有若干槽點三天三夜都說不完
看了一下新特性,毫無進一步了解的慾望。
對比一下C++11的更新:auto,lambda,增強的for循環,智能指針。。。都是拿來就用的好東西,一用起來C++立馬變成一門現代語言。再看看C++17,傳說中的的concept,module,range都難產了,反倒是新加了一堆只有語言律師才想去學習的特性。我是做機器學習的,對於我來說,C++17的新特性一個都用不到。
C++每一個新標準給我的感覺就是:卧槽,原來之前C++里還沒有這玩意。
對於我來說:
variant 有用
filesystem 我不是很懂這都2017年了,std居然才有std::filesystem。。。
parallel 特別有用
template& 特別有用但是我不怎麼常用。
剩下的都用不到。
沒有想像中的好。。。。畢竟我還是期待過module和concept的。。。。
C++20見
c++一路走好,天堂里不用兼容舊版本
代碼規範裡面又要增加一些禁止使用的特性了。
rust歡迎你(霧)
這個問題下的不少回答真是讓我有點生氣。為什麼這麼多人都只看到 C++ 變複雜的地方,卻不往補漏、簡化的地方(題目鏈接里的內容)看兩眼呢。
我對 C++17 的語法特性改變就一句話評價:
增加特性,以簡化用法。
不過這個方向是很難做好的,而且看起來不是個收穫好評的方向。
為什麼感覺大家那麼抵觸呢?C++17明顯在易用性上面有挺大的進步的啊。不過我期待的幾個東西一個都沒來。。。氣。
估計等到C++20的時候,如果他們不拖延了,C++就完美了。
------------------------------
最近寫C#的時候才感覺到寫起來有多爽,基本上寫完代碼就可以直接按照我的想法運行。而且就算出錯了,很容易就能查出來。
回想之前寫了那麼久C++,總是有奇奇怪怪的錯誤,要麼內存的錯誤,要麼模板匹配的錯誤,最後查錯花的時間實在是太多了。
但是,
我還是最愛C++,雖然C#寫起來爽,Python寫起來更爽,JavaScript寫起來更更爽,但是,我還是愛C++,畢竟看過C++的漂亮代碼之後,感覺C++也是可以寫出來非常好看易懂的代碼的,而且不用在GC的時候卡頓一下,雖然C#、Java什麼的優化一下代碼也可以不怎麼卡頓,但是麻煩程度和寫C++也差不了太多。
C++14: Better C++11.
C++17: Better C++14.
C++20: ...
推薦閱讀:
※C/C++中相同的浮點數的內存布局一定是一樣嗎?
※只使用 C++ 標準語法和標準庫如何做出優美的人機界面?
※如何用 C++ 在 10 行內寫出八皇后?
※C/C++該採用怎樣的命名規則才能讓自己的代碼足夠清晰呢?
※如何才能學到Qt的精髓?
TAG:C |