標籤:

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,

  1. C++17 沒有變得更像一門現代語言;
  2. 機器學習領域的 C++ 用戶沒有 benefit from C++ 的新特性。

1) 是很嚴重的批評。如果真是如此,說明我們沒有 evolve 這個 language. 下面我用兩個例子說明不是這麼回事。

Structured binding

std::map& m;
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 頁紙:

  1. Mathematical Special Functions. 這俺不懂,不過如果要自己實現,得雇幾個 PhD.
  2. Parallel STL.

在講 Parallel STL 之前,我需要導入一個觀念上的轉變。也許過去你們認為只有 libstdc++, libc++ MS STL 這些才算 C++ 標準庫實現,但隨著這些年 C++ 標準庫開始向專門領域擴張,傳統完整標準庫的實現質量會收到這些領域的高水平 vendor 的挑戰,比如,一個只實現了 & 的庫,性能數倍於其它實現,這都是有可能的。這時候標準化的作用仍然能惠及最終用戶,只要這樣一個只實現了一部分的庫是 standard conforming 的,切換到高質量的實現最多是換一下 namespace 的事兒,或者甚至是你的 toolchain 支持這種切換。

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 guide
Thingy thing{"A String"}; // &<------- thing.t is a `std::string`.

這真的是在 deduction 嗎?不如說有點無中生有的味道。但如果我給這個特性換個名字,叫 specialization selector, 你就明白了,上面的 Thingy& 就是用戶寫出 Thingy("A String") 這樣一行代碼時的 preferred specialization. 反過來,從介面設計的角度來看,class template argument deduction 這個特性真正提供的,是一個形如 ClassTemplate(args...) 的全新介面,它的功能可以完全定製,只要這個功能是由 ClassTemplate 的某些 specialization 提供的(「某些」是什麼意思?主模版沒有的, explicit specialization 造一個),根本不用順著 deduction 的思路來。比如你有這麼一個模板類,

template &
class Tasks
{
Tasks(Queue q, F on_finished);
};

本意是允許用戶自己定製 Callback 的類型,結果用戶寫

Tasks(v, []{ cout &<&< ...; });

得到一堆各不相同的 Tasks&, 放不進同質容器。但只要有這樣一個 guide

template &
Tasks(Queue, Fn) -&> Tasks&&>;

用戶寫上面的代碼時就會選擇到 Tasks&&> 這個 specialization, 然後嘗試用 lambda 初始化 std::function&, 達成「用戶可以自己指定 Callback 類型,默認使用 type erasure 」,給 API 增加很多彈性。

但要用好 deduction guide, 不但要在頭腦中打破常規,還需要掌握它和 class template argument deduction 的各種規則,不是那種我一貼代碼,別人就能用上的特性。不過我對其在擴展我們 abstraction 方面的前景很有信心,一大波精心設計過的 ClassTemplate(args...) 介面有望到來。


我的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 // 來晚了,大家的輪子都造好了。現在在標準庫裡面加入對操作系統的封裝的東西,意義已經不大了

我覺得那些以後一定會流產的TS,當然我並不是在做預言:

  • concepts

  • coroutines

  • networking

  • 2d graphics

大概意思就是說,如果發明一個語法糖,不能顯著減少麻煩的(lambda就是一個正面例子),或者性價比不高的(譬如concept,白白增加了編譯器的複雜度,然而模板本來就沒多少人能學會),那留著也只是膈應編譯器作者而已。等到以後實在太複雜維護不了了,都得GG。


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& var{1};
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& 這種語法,表明 T 滿足 ForwardIterator。那麼按照上述理論 template& 不應該表示不限制 T 么?搞出 template& 這種不倫不類的東西,而且 C++ 的非類型模板參數就不支持自定義的 Literal class,所以這個特性用處真的太小了。。另外這玩意又走上了 C++ 的老路——標準庫沒有用上。

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&::length/compare 不是 constexpr 啊!沒法搞出完全 constexpr 的 string_view 啊!大家一看怎麼辦,得,開始搞什麼編譯器 intrin。。。

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 matching

filesystem 有點用

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 |