2009-09-29 77 views
3

它曾經是在C++中使用模板類的,實現必須在頭文件中,或者#included到底部的頭文件中。C++模板:頭文件仍然破碎?

我幾年沒用過C++模板;我剛開始再次使用它們,並觀察到此行爲似乎持續存在。這仍然是這樣嗎?或者編譯器現在是否足夠聰明以便將實現與接口分開?

+0

即使出口,你仍然不會避免不釋放源代碼(以任何形式)。 EDG文檔說:「.et文件只告訴前端關於導出模板定義的位置;它們實際上不包含這些定義。因此,包含導出模板定義的源必須在實例化時可用(通常,特別是出口工具不是一種避免以源格式發佈模板定義的機制。*「(由我強調) – 2009-09-29 13:57:07

+0

@litb:這太讓人生氣了。但是,謝謝你的回答。 – 2009-09-29 13:57:53

+0

我實際上沒有實現一個編譯器,所以我沒有這樣的說法,但我相信EDG的創造者:) – 2009-09-29 14:29:47

回答

2

要將執行與聲明分開,標準強制您使用export關鍵字。據我所知,只有一個編譯器知道如何處理它:Comeau。

但是,C++ 0x將包含一個機制,告訴編譯器不要自動實例化某些特化(extern模板)。所以,如果你想縮短編譯時間,你可以通過在一個編譯單元中明確地實例化一些特化並在頭文件中將它們聲明爲extern來實現。

2

您指的是導出的模板(使用export關鍵字),這似乎僅由Comeau C++支持(根據C++ FAQ Litethis section)。

保持界面沒有實現代碼的常用技術是將內聯函數定義放入一個單獨的「實現」頭中,該頭可以包含在聲明頭的末尾。

+0

說實話,我本來不是在尋找出口。我只是在尋找標題,而不必在其中包含模板實現(像其他語言功能一樣)。 – 2009-09-30 00:06:37

1

導出只支持EDG前端,商業上只有在Comeau編譯器中可用,據我所知。

導出不會消除源泄露的需要,也不會減少編譯依賴性,同時它需要編譯器構建者的大量工作。

所以Herb Sutter本人要求編譯器構建者'忘記'導出。由於需要投入的時間在其他地方會更好......因此,我不認爲在其他編譯器看到它花費了多長時間並且獲得了多少資金後,出口將不會實現。

這篇論文被稱爲「爲什麼我們買不起出口」,它在Sutters blog上列出,但沒有pdf(儘快谷歌應該把它翻過來),現在已經六年了,我想他們都聽了,打擾:)

很多人使用兩個頭文件(例如.hpp.ipp),一個只有聲明,一個帶有定義,那麼它只是一個包含另一個的問題。

foo.hpp

#ifndef MY_TEMPLATES_HPP 
#define MY_TEMPLATES_HPP 

template< class T > 
void foo(T & t); 

#include "foo.ipp" 
#endif 

foo.ipp

#ifdef MY_TEMPLATES_IPP 
    nonsense here, that will generate compiler error 
#else 
#define MY_TEMPLATES_IPP 

template< class T > 
void foo(T & t) { 
    ... // long function 
} 

#endif 

這隻漲幅比較清楚,當然,沒有什麼變化相比,只是在一個頭文件內聯的一切。

+0

找到您參考的pdf:http://ra.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1426.pdf,日期爲2003年3月 – 2009-09-29 15:42:29

+0

@Matthieu M.:PDF似乎已損壞。最好拿到原文:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1426.pdf – paercebal 2011-12-26 17:46:28

+0

@paercebal:謝謝! – 2011-12-27 17:16:56

3

從技術上講,他們不需要需要在頭文件中。

這種用法的一個例子是當你有一個固定版本的模板類(可以說參數爲char和wchar_t)。然後你可以把所有的方法解析放到一個源文件中,並顯式實例化這兩個版本。這樣做的安全性是其他人不可能爲它不打算用於的類型提供模板。

// X.h 
template<typename T> 
class X 
{ 
    // DECLARATION ONLY OF STUFF 
    public: 
     X(T const& t); 
    private: 
     T m_t; 
}; 

// X.cpp 
#include "X.h" 

// DEFINTION OF STUFF 
template<typename T> 
X<T>::X(T const& t) 
    :m_t(t) 
{} 

// INSTANCIATE The versions you want. 
template class X<char>; 
template class X<wchar_t>; 


// Main.cpp 
#include "X.h" 

int main() 
{ 
    X<chat> x1('a'); 
    X<wchar_t> x2(L'A'); 
    // X<int>  x3(5); // Uncomment for a linker failure. 
} 

假設人不能只包括直接X.cpp(因爲它沒有被分配提供),那麼別人就無法使用X < int>的或X <浮>等。但abovr類是完全支持定義。

我也看到這種技術用於減少編譯時間。因爲每個編譯單元都不會重新生成相同版本的X,所以我們只能在一個地方得到定義(因此一個編譯成本)。縮小到這個是你必須手動instanciate你使用的每個分離版本的X.

+0

這很漂亮,雖然它沒有做我所需要的。不過,我會記住它的。 – 2009-09-30 00:02:22

0

除非您明確實例化所有模板,否則GCC會經歷漫長的收集階段。 VC++似乎應付,但我寧願避免這一步,並在我知道如何使用模板的情況下,這通常是應用程序的情況,而不是庫,我把模板定義放到一個單獨的文件中。這也使得代碼更加可讀,使得聲明更少地與實現細節混雜在一起。