最近更新: 2006-12-19

C++ library 的發展困境, part 2

jeffhung 在 HEMiDEMi 中回應:應該是因為不懂 template 的奧妙,才會覺得「C++ 中有一層厚厚的濃霧將 template 包圍起來」吧?(HEMiDEMi - 共享書籤 - C++ library 的發展困境)。我其實很欣賞 template 的概念,卻也因此我才說 template 是「C++發展困境」的原因。

如迷霧般奧妙的 Template

C++ 的發展困境在於 library 的發展速度慢 (Bjarne Stroustrup 說的) ,所以需要更多人投入這份工作。而我覺得「奧妙的 template 」很難搞,所以很多人心有餘而力不足。算算資歷,我在 1996-2002 年這段期間,用 C/C++ 在 Linux/FreeBSD 下寫系統程式,那時候 template 與 STL 還在討論及推廣階段,可是我依然用 C++ 用的很開心,還把很多 C library 封裝成 C++ class (沒用 template)。後來興趣轉到 web application ,玩起 Perl/PHP/JavaScript 等各種動態程式語言。隔了幾年沒用 C++ ,暮然回首發現 template/STL 突然長大了,感覺非常陌生。

Steve Donovan 在《Overdoing C++ templates》中描述的情形,正是我所謂「C++ 中有一層厚厚的濃霧將 template 包圍起來。或者反過來說,是 template 用一層厚厚的濃霧將 programmer 包圍起來」的感覺。有時候我可以很抽象的操作一個 object ,但有時候又必須關注到具體的細節,這種忽隱忽現,若即若離的感覺,真的很不好。無獨有偶,我也同 Steve Donovan 一般,喜歡用自定的 string class 取代 std::string ,顯然我們都不喜歡這種感覺。我這種佔程序人員多數比例的中階 programmer 都會被排擠在 template class 的大門外了,不正表示 template class libaray 是少數人才有能力開發的嗎?

其他程式語言不需要 Template

很多動態程式語言,包括比 C++ 早出現的 Smalltalk ,沒有奧妙的 template 一樣漂亮地完成同樣的工作。 Armin Roehrl 整理了一張比較表:Ruby versus Smalltalk versus Objective-C versus C++ versus Java versus Python versus CLOS versus Perl5 versus XOTcl 。從中可以發現 Template 是 C++ 獨有的特性,Ruby, Smalltalk, Python 等則是 Not Needed

那些動態程式語言讓 programmer 覺得寫 library 和 application 是一樣的事,自然 library 甚至是 framework 都能快速發展出來。代表性例子就是 Ruby 和 Ruby on Rails 。反觀 template 曲高和寡, C++ 如何冀望更多人參與 libaray 的開發工作?

樂多舊網址: http://blog.roodo.com/rocksaying/archives/2583288.html

樂多舊回應
yeychang@yahoo.com.tw(Simon) (#comment-15311863)
Tue, 18 Dec 2007 01:02:51 +0800
Hi :
你好,不知道直接叫你石頭成,可以嗎?
有一問題想請教您,關於撰寫C++ Library 的書籍是否可以推薦較好上手的,以及該如何去學習撰寫,謝謝!!
對於C++ Library 搞不定的菜鳥 Simon
mikimotoh@gmail.com(Miki) (#comment-21131915)
Tue, 24 Aug 2010 16:04:24 +0800
在我上一個做的工作裡,我引入了STL、Boost,我那時教條地認為這是業界潮流,認為所有組員都應該一樣跟我學會template metaprogramming。

但後來做另一個計畫時,改用python這種軟型別的語言,驚覺到以前在C++需要複雜的技巧的程式改用python就可簡單地表達出來。我也在不斷省思說為了run-time 效能而要把「多型」搬到compile-time的這種metaprogramming技巧是否真有必要。

比如,記得在boost metaprogramming有提供一個功能,可以在compile-time就把binary bit-string,如 0011 (不加雙括號) 轉成integer 3。

其實template跟virtual function都是讓演算法可以處理多型物件的技巧,只不過一個是compile-time,另一個是run-time。我認為C++應該演化出一個更泛用的語法來實作多型,使得程式員不需要區分要用template或是virtual function實作,那就更好了。

我建議是只要給compiler一些hint,比如"compile_time",就能讓compiler自動判斷這個演算法或物件能不能在compile生成(template specialization),如果不能就警告或錯誤。

總之,讓複雜的留給電腦,簡單的留給人類。
未留名 (#comment-21133501)
Wed, 25 Aug 2010 01:03:18 +0800
Scott Meyers 在 Effective C++ 這本書中,將 C++ 語言劃分成4個領域語言,即 C, OO C++, Template, STL 。每個領域都有各自的使用策略。然而,並不是每一件專案都會同時涉及這四個領域,也因此並非每個程序員都有機會熟悉這四個領域。

我個人一向把 C 和 C++ 的程式劃在同一類。但嚴格說來,就我維護過的 C/C++ 程式中,九成以上屬於 C 與 OO C++ 。涉及 template 和 STL 的不到一成。所以各有所偏,其實也是很合理的。

就我所知,C++ compiler 是目前的程式語言中最複雜的了(Java compiler 則是我眼中的 lazy compiler)。你最後的建議,現在 C++ compiler 其實也做到了。只是它只能提出警告訊息,而不能告訴你是否有更好的解法。

不過呢,聰明的 C 程序員早就想出救贖之道了。那就是用 C 語言寫出其他程式語言處理那些複雜的工作。
mikimotoh@gmail.com(Miki) (#comment-21134025)
Wed, 25 Aug 2010 11:11:02 +0800
現在的C++ compiler有做到我所說的這一點?

我再舉例好了。

C++ metaprogramming 可以做出 fibonacci,請見:

http://knanshon.blogspot.com/2006/05/c-meta-programming-fibonacci-and-phi.html

它主要是用 template specialization的特性,來做到像if-else的分支,還有用到recursive。

但是fibonacci的演算法很簡單,要用template metaprogramming寫就很複雜。但這樣變複雜有何好處呢?只是為了讓某些可在compile-time就知道的算式(參數為常數)搬到 compile-time來做,而不要拖到run-time才做,提昇點執行效能。

你所說的「compiler有做到」,我想你指的是否為 optimization,不過這是各家compiler做的最佳化,而不是語言的規範。

再來另外,template metaprogramming無法接受參數為string。如果要用meta-programming寫個STRLEN("abc") 肯定是不行。

我所希望的是,程序員不需要寫兩套fibonacci,一套是run-time用,一套用是compile-time(用metaprogramming寫的變複雜了),他只要寫一套就好,而由compiler自行生成。當程式員給予hint希望在compile-time而compiler做不到,compiler能給予警告。
未留名 (#comment-21134813)
Wed, 25 Aug 2010 17:09:32 +0800
就我所知,如果不考慮效能最佳化,很多演算法的 template 其實不複雜。
某路人: 啊,不就是浪費時間在 copy, destroy 嘛。(挖鼻孔)

在邏輯上,Compiler 其實無從得知何謂「效能」,它只是忠實地按程序員的指示做事。除非我們能教會 compiler 什麼叫「效能」。我想這已經是 AI 領域的事了。

C++ 程序員對「效能」的這個字眼是很敏感的,這就形成了一個有趣的現象。用 C++ 程序員眼中沒有經過特化的 template 演算法所產生的程式,也就是所謂「效能差的程式」,它的執行效能其實還是優於用動態語言設計的同樣演算法程式。

許多動態語言的設計哲學就是,隨著計算機計算速度的提昇,把工作時間用來提高程式的生產效率,而不是去最佳化某特定項目的演算法。用 C++ 的術語來說,就是「雖然這個演算法template的效能不好,但把它交給計算機的計算速度解決,我們就別浪費時間在 specialization 上了」。
yuri@hotmail.com(tiara) (#comment-22615780)
Thu, 13 Sep 2012 16:57:39 +0800
>程序員不需要寫兩套fibonacci,一套是run-time用,一套用是compile-time
這已經可以做到了,因為C++11已經引入了constexpr

constexpr factorial (float n)
{
return n > 0 ? n * factorial( n - 1 ) : 1;
}

如果你輸入的數據是常數,則可以在編譯時間算出來
若不是,則會轉成在執行時間計算
更贊的是這些常數不再限制於整數,連浮點數也可以支援,帥啊