2011-05-28 74 views
24

顯然,模板庫只需要標題,但對於非模板,什麼時候應該只做標題?什麼時候應該考慮製作庫標題?

+2

當你不介意暴露你的IP。 – Nim 2011-05-28 22:50:59

+0

@Nim:它是Boost軟件許可下的開源程序,所以我當然不介意。 :) – 2011-05-28 22:55:09

+0

@比利:哦,你進入了Boost?格拉茨? :P – Xeo 2011-05-28 22:57:44

回答

14

如果您認爲您的非模板庫可能僅包含標題,請考慮將其分爲兩個文件,然後提供第三個包含.h.cpp(包含後衛)的文件。

然後,任何人在很多不同的TU中使用您的庫,並懷疑這可能會花費大量編譯時間,可以輕鬆地進行更改以對其進行測試。

一旦您知道用戶可以選擇使用該庫的方式,答案可能會變成「只要可能就可以提供該選項」。幾乎任何時候,包括來自多個TU的內容都不會違反ODR。例如,如果您的非空函數引用了全局變量,那麼您就不幸運了,因爲不同TU中該函數的不同定義會以相同的名稱引用不同的對象,這是違反ODR的。

+2

Oooh。從來沒有想過這樣做。 +1當'.cpp'爲'#include'd時,你如何正確地將函數聲明設置爲'inline'? – 2011-05-28 22:54:20

+2

@Billy:在第三個文件(第二個.h)中設置一個'#define',並在.cpp中設置#ifdef _____ #define DO_INLINE inline #else #define DO_INLINE#endif'。 – Xeo 2011-05-28 22:55:56

+1

或者只是將它們標記爲'inline',它不會造成任何傷害。 – 2011-05-28 22:58:06

-2

如果沒有模板,你會在頭文件中有實際的定義。這意味着如果兩個文件包含你的頭文件,你會得到多個定義,並且代碼不會被編譯。

換句話說,將定義放在標題中是一個非常糟糕的主意。你應該堅持只聲明和模板。

至於模板,編譯器知道你可能會多次包含相同的頭文件,它們不會一遍又一遍地生成相同的代碼。

編輯:如果你的意思是「保持一切內聯」,我認爲這是一個非常糟糕的做法。頭文件變得完全不可讀,實現中的任何更改都會強制庫的任何用戶重新編譯所有內容。

+0

-1:這是不正確的。只要內部鏈接,您可以將定義放在標題中。 (例如,它們被聲明爲「inline」) – 2011-05-28 22:56:05

+0

'inline'。 'nuff說。 – Xeo 2011-05-28 22:56:24

+0

有時,需要重新編譯每一個變化並不是這樣的限制。 – 2011-05-29 03:18:18

0

模板庫不需要僅用於標題:實現可能包含一些獨立於模板參數的部分,並且由於某些原因(例如較少的代碼大小)被分離爲特殊的二進制文件。

我無法想象一個非模板庫真的必須是僅標題的情況。但是有時候,允許內聯所有代碼可能是合理的性能。一個例子可以是圍繞特定於平臺的接口的包裝庫,例如用於像同步原語,線程本地存儲,原子操作的平臺和編譯器特定實現等。

+0

Alexey:向我展示一個不是** header的STL庫。而對於STL,我的意思是容器/算法/迭代器部分,而不是整個標準庫。 – Xeo 2011-05-28 23:04:27

+0

也許,但模板庫的模板部分只能是標題。模板定義需要存在於翻譯單元中,以便編譯器可以實例化它。一些STL具有二進制部分,主要是因爲A.它們被包含爲一般C++運行時的一部分,該運行時具有非模板片段(例如'libstdcxx'),或者B.它們包含不是模板的組件。至於性能方面,大多數編譯器現在都有鏈接時間代碼生成,這幾乎消除了發佈版本之間的性能差異。 – 2011-05-28 23:04:49

+0

@Xeo:好的,你可能是正確的,STL和語言支持庫不一樣。 – 2011-05-28 23:09:05

3

您可以按照Boost.Asio的指導。

他們只是提供了兩個版本的庫:header-only和header + library。

他們在包含頭文件之前用一個宏定義(或不​​包含)。我認爲默認(如果沒有定義的話)是使用純標題版本。

請參閱Optional Separate Compilation

注意它們是如何巧妙地提供一個單一的源文件來編譯定義的一切或與動態加載庫鏈接的選項。

相關問題