標籤:

如何評價 Herb Sutter 的 C++ 提案:metaclasses?

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0707r0.pdf


從type traits開始就知道,這種東西遲早有人要搞出來的。

但是為什麼早不搞呢?非要在SFINAE、Template 和 Concept 上兜兜轉轉。

重新搞一門語言叫CMFL吧。

平時可以叫 C++ meta-functionality language,
高興了可以叫C++ make-funny language,
不高興了可以叫C++ mother-f**ker language。

從本我到超我都完美解決了各類C++使用者的需求。


Herb Sutter來Qt Oslo辦公室宣講的時候,大家(其他同事)反應好像還不錯,^_^


啥時候加入template metaclass讓metaclass支持參數化啊。

template&
$class mixin
{
...
};

mixin& Shit
{
...
};

==========

又細看了一遍,原來已經打算包含進去了。

其實相當於搞了一套針對class的宏,能夠更自然地利用static reflection的信息來開心地艹代碼。

HS終於在追趕AA的路上又邁進了一大步啊。希望他們能夠勝利會師。


期待 templated metaclass, partialized templated metaclass, meta-template-class, rank-N metaclass, metaclass-traits


AA:我說啥子來著


正在讀。

感覺很認同這個proposal的開頭的一段話:如何往一個複雜的系統里東西而讓它變簡單呢?加一層正確的抽象。

第一感覺是metaclass像是一層正確的抽象。過去的template和move semantics似乎也是。

相比之下,SFINAE可能不是,而像是一個implementation detail被迫標準化成為的feature。

我還沒想清楚metaclass有多powerful,比如能不能拿來重新實現目前template的大部分功能……注意到現在的partial specialization的語法依賴於SFINAE,其實是個挺噁心的玩意。如果這也能做到的話就牛逼大了。


C++ 太複雜了,我選擇放棄(手動再見)

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

還是說幾句吧。

放棄 C++ 其實不是因為太複雜,而是因為坑太多了。C++ 總是不斷地加新東西來補前面留下的坑,卻也使得坑越來越多。

這個 metaclass 看了下,簡直就是把 C++ 編譯器變成一個用 C++ 語法寫的用來生成 C++ 代碼的腳本語言解釋器了。如果 C++ 要複雜到這種程度,我為什麼不用個專門的預處理器來處理 C 啊,或者甚至發明一個編譯到 C 的語言,這樣還能保證 ABI 兼容性……


很多人總說C++越來越複雜,可是只是寫寫業務邏輯的話,這些新加入的特性能有多大影響?

這提案就算通過了,平時寫代碼不見得有多大區別,依我看就是以前用庫要記得用對應的宏,現在用庫要記得用庫給予的關鍵字罷了。

真正麻煩的倒是寫最底層庫的人,他們又要花時間精力學新的語法新的規則,然後可能要維護新、舊、遠古…多套代碼。

不管怎麼說,這總比現在的SFINAE強。

我只是想找個工具用,不想也做不到了解這個工具的設計思想、製作材料、製作步驟等。而從上手的難易度與自由度來看,前者明顯更好。

不過考慮到concept、module都沒接受,我看這玩意兒還是期待2030年能通過,2050年普及吧。


某種意義上類似於把moc標準化?

但是相比於現有的moc,不太能看出這種metaclass的明顯實用的優勢是否蓋過它的複雜度。C++需要這麼多的元編程方式嗎。考慮到已有的方式(包括討論中的static reflection),需要再加入新的元編程方式嗎

看了 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0425r0.pdf ,稍微了解得多了一點,看來標準委員會是真打算著重考慮constexpr programming和homogeneous value-based programming,上次和這次meeting都有不少paper是針對這方面,提出一套只能在編譯期用的設施。編譯期的調試器指日可待

但是如果用戶有這種程度的元編程需求,為什麼不直接找個有libclang綁定的腳本語言


昨晚簡單看了整個proposal,有一句話令我印象深刻,C++到底缺少了什麼,以至於pair不能簡單的寫成

template&
struct pair {
T1 first;
T2 second;
};

我覺得這個proposal就是這個問題的答案了吧

metaclass的思想是這樣的,以往編譯器看到一個類定義,會去根據自己的邏輯去為這個class補充需要的東西,比如,看到struct,會轉寫為一個全public的class,看到一個pod,會自動轉寫默認的構造/賦值函數。

而metaclass,意在向程序員暴露這個機制,允許程序員指定編譯器在轉寫時的行為,有一點接近於清潔宏。

proposal里給出了各種例子用於描述metaclass的能力,包括interface,value_type,甚至final和基本的class,struct關鍵字都可以用metaclass來描述。

但是本質上metaclass還是根據指定的規則自動為class擴充內容,有一點類似於haskell裡面type classes的默認實現。

後面提供了is和as兩個方法,is用來判斷,as用來創造別名,可以通過as來修改已有的東西的定義。

最後吐個槽

終於忍不住開始教編譯器怎麼顯示錯誤信息了嗎

C++

用戶自行管理內存、對象所有權和生命周期、硬體抽象……和編譯器報錯信息?


從美學角度來看,是非常漂亮的特性;從實用角度來看,是很有意思、有用但又不太有用的特性。

花10分鐘大致看了一下,思想挺不錯。不過在現在的C++這樣一個龐然大物里,再增加任何語言特性都是傷筋動骨的事。特別是metaclasses如何跟別的重要語法特性配合,paper里完全沒說明白(也可能是我看得不細漏掉了,歡迎指正),舉兩個例子:

1. metaclasses和concepts分別怎麼定位?雖然paper和博客里都說前者是後者的補充,但細想其實並沒有真正回答這個問題。具體來說,interface(或別的metaclasses)能否作為模板參數?比如:

template & class Action {};

如果能的話,那concepts估計就不會有多少人用了,我只要按需要實現自己的metaclass就可以代替之;如果不能,必然會有需求要限定模板參數為某個metaclass,那還得再手動搞一個和該metaclass相同含義的concept?

這是個人認為最大的問題。Herb Sutter博文下也有個哥們問了類似的問題,Sutter仍然回復說「前者是後者的補充」,實乃官方辭令,這兩者之間定位必然會有一定重合。metaclasses如果先進了標準,concepts就沒必要進了,或者就是兩個特性整合起來,再弄個十年八年一起進。

2. metaclasses和模板如何配合?比如我定義一個

template & interface Buyable {};

假設要做specification,是否能針對int特化為class或別的metaclasses?比如:

template &<&> value Buyable& {};

這個我覺得應該是能的,concepts也會有類似問題。畢竟,永遠不限制你給自己挖個足以摔斷腿坑,這才是C++…

不管如何,metaclasses如果真能做好,確實是個非常好的特性。還記得十幾年前初學Qt的時候,當時用慣了MFC,對這種類層次複雜,宏滿天飛的重型框架非常厭煩,你在其中絕對看不到任何現代C++(當時的現代C++是C++98/03)的痕迹。所以第一次用Qt頗為驚艷,感覺這才是真正的C++,唯一的缺點就是需要moc,但如果沒有語言潔癖的話其實還好。當時雖然有很多基於C++的GUI框架,但總不如Qt給人的感覺之好,至少Qt里你可以看到自己的main函數,和CLI程序一致,這對GUI開發入門者來說可是非常重要的。

同一時期隨.NET流行了一陣的managed C++以及C++/CLI也和Qt類似,搞了一大堆語法擴展,讓人覺得鍾愛的語言實在不行之極,已走在淘汰的邊緣。幸虧隨著iphone誕生,桌面軟體這個產業自己很快就被淘汰了,而C++憑藉自身的優勢,在互聯網和AI這樣的朝陽產業迅速站穩了腳跟。

如果回到十幾年前,C++有了metaclasses,當年Qt和C++/CLI中那些令人遺憾的部分就可以完全基於C++來實現,看起來會很美,給人感覺不錯。但現在已然時過境遷,今日之天下,沒有metaclasses一樣可以過得很好。


太過分了啊。C++不能把meta programming玩得太過火,走火入魔啊。其實D語言和F#早就有這個功能了,人家是怎麼做的呢?

說來這麼多實現,我最喜歡F#的那個。F#是這麼做的:首先你寫一個類(繼承自ITypeProvider),他的結果就是拼裝一個新的類,然後單獨編譯它,最後當成編譯器的插件引用到你的項目裡面。多開心!debug的時候也非常方便,運行時出了問題,反正是.net的,反編譯出來都是代碼。最後發現是生成的部分出了問題,就直接去debug生成器。開發過程無比流暢。

人家最後給出來的demo是,可以直接import一個connection string,然後一個ORM的東西就出來了,語法也超級好看。

然而C++做成meta class就完全使用來惹麻煩的,C++不能什麼問題都追求在同一個項目里解決。別的什麼都不說,我就問一句,這種代碼要怎麼debug?


沒看完原proposal就評價的都是耍流氓。這個問題下的回答中提出的幾乎所有疑問和質疑都能在原文proposal中找到相應的回答和解決方案。

我讀完proposal了,說一下感受:這份更新會讓C++變得更簡單易用也更高效。


不管怎麼看,語言靜態可解釋性的增強以及更小粒度的約束能力都是高級程序員所喜愛的功能,只是c++上增加了太多ad-hoc的語言特性以及不可閉合的語法特徵會讓局面變得越來越複雜。

提案的一開始就強調語法功能需要一致性,正交性,通用性三大特徵,但現在這種局面下似乎很難保證。應該好好理一理,那麼多現有複雜特性演變出來的目的究竟在哪裡,靜態能力的邊界究竟在哪裡,或者靜態部分是以何種方式分別和代碼已經程序員之間進行交互的。簡單一個const-expr什麼都往裡塞恐怕會把問題搞的糟糕,而且依賴於底層類型系統的可解釋性,這一點目前來看不是c++的長處,那一堆traits總是讓人很擔心,同時這種依賴於class方式組織代碼侵入式有點強,和面向對象的其他機制一樣不夠靈活。如果給予程序員更高的控制能力,我覺得更應該以另外一個層面的特徵,比如宏或者ast等等之類的,來進行交互。

我們更需要一個小而緊湊的語言核心,並重新在此基礎上演變出那些更具有解釋性的語法特徵出來。


所以還搞啥反人類的type_traits,metaclass這東西Qt不造多少年前就搞出來了,我都用了好幾年了(哈欠表情)


這東西弄下去,說不定可以取代內建的虛函數/虛基類生成機制,在導出/導入 extern "C" 函數時提供用戶定義的 name mangling 。

這樣一來用戶或許有可能直接搞出自己的一套可移植 ABI ,(若不考慮遺留代碼)以後 C++ 程序員有可能不用再受 ABI 不兼容之苦了。


以前我也想過,如果要弄一個系統編程語言但是又支持一些高級特性的話(比如反射),必須得這樣搞。比如,某些class有元信息,有些沒有。這樣的話如果你想用對象類型的反射的話就好辦,如果你想自己定義內存緊湊的值類型也可以。符合C++的精神(You don"t pay for what you don"t use)。

這種metaclass也可以說是對類型生成的一種模板化。也就是說從此以後可以生成各種class。

實際上除了帶反射的Qt類,現在C++的類也有很多是遵從了某種類型設計模式的。

比如

對象類型:可繼承,不複製,不移動。(widget,abstract_item,shape)

值類型:可複製,可移動,不繼承 (color,vector,complex)

資源句柄類型:不繼承,不複製,可移動(unique_ptr,socket, file_handle)


程序猿指導編譯器編譯程序猿的代碼


我都懶得看具體內容了。c++是我花大力氣認真學習的開發語言,也已經形成自己的開發套路,不想再折騰了。


感覺需要一個元類函數了,只是繼承的話組合度還是不夠。

其次,元類中能不能調用模板和constexpr函數例如 is_pod&之類的。。。。

港那麼多,還是在畫餅而已。。。。。雖然感覺好好玩,但是C++20有沒有戲呢(感覺大有可能)

還是帝球說得對,港到底不如scheme,逃


操作AST不(

-&>Sort?


還好我十年前就放棄了C++。

話說都弄成這樣了換個語言不好嗎?


推薦閱讀:

C++20有望實現自動PIMPL嗎?
如何評價c++的協程庫libgo?
為什麼一般要用#include「xxx.h」?
模塊相比於 #include 指令的優點是什麼?

TAG:C |