2013-02-21 44 views
0

相當長的一段時間,我用老的-C++分離自定義模板化功能的實現的問題作鬥爭。 C++ 0x」爲extern似乎是一個解決方案,但我不能將其應用正確的extern模板的構造函數在C++

我的代碼:

main.cpp

#include <iostream> 
#include <string> 

#include "lexer.h" 

int main(int argc, char const *argv[]) { 
    std::string foo("foo"); 
    new lexer((foo.begin()),(foo.end())); 
    return 0; 
} 

lexer.h

#ifndef lexer_h 
#define lexer_h 
class lexer { 
    public: 
    extern template<class InputIterator> 
    lexer(InputIterator i, InputIterator end); 
}; 
#endif //lexer_h 

lexer.cpp

#include "lexer.h" 
template<class InputIterator > 
lexer::lexer(InputIterator i, InputIterator end) { 
    //make it work 
}; 

g++ main.cpp lexer.cpp -std=c++0x編譯。我想稍後使用對象文件。

因此,如何將它看起來固定的嗎?

+0

我不認爲模板的extern可以解決您所問的問題。 – 2013-02-21 16:27:36

+0

@DavidHope因此'似乎',因爲我不知道太 – Valerij 2013-02-21 16:33:09

+0

好吧,所以根據這個鏈接http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=549,extern模板專門用於消除模板化對象的潛在代價昂貴的多重實例化(就像.h文件中的'extern'語句只是告訴代碼該變量是在其他地方定義的),這不是修復在.cpp文件中實現模板函數的方法。實現必須仍然在.h文件中(因爲它必須被編譯爲每個實例對該類都是唯一的) – 2013-02-21 16:36:40

回答

0

爲什麼它不工作的原因是你沒有實例化類模板,你也不是實例化類模板的構造函數:如果處理調用該構造的翻譯單元(即.cpp文件),比lexer.cpp等,編譯器將無法看到它的定義,所以它不會爲它發射任何對象代碼;而另一方面,在僅平移單元可以看到它的定義(lexer.cpp),你是不是調用構造函數,如此反覆,編譯器不會發出任何目標代碼。

結果,爲你的構造並沒有目標代碼存在於你的程序的編譯翻譯單元,並試圖創建可執行文件時鏈接器會抱怨分辨的引用到類的構造函數。

extern關鍵字用於防止在一個翻譯單元模板的實例化(即使它的完整定義是可見的!)當您知道,這將是(明確)實例化的另一個翻譯單位,從而節省編譯時間。澄清請參閱this Q&A on StackOverflow

從第14.7.2/C++的11標準的2:

爲顯式實例的語法是:

顯式實例: 的extern(OPT)模板聲明

顯式實例化有兩種形式:顯式實例化定義和顯式實例化聲明。明確實例化聲明extern關鍵字開頭。

因此,你所提供僅僅是一個聲明。沒有貶謫的.cpp文件類模板的成員函數的定義,而不從連接器獲得未解決引用錯誤的方式,除非你實例化它們(可能通過類模板的顯式實例化),在同樣的翻譯單元(唯一可以訪問這些定義的一個)。

C++ 03有一個名爲export的關鍵字,它可以做你正在努力實現的目標,但是在C++ 11標準化期間允許做it has been removed,因爲它證明對於編譯器供應商來說太難實現了。

1

除非您知道用作參數InputIterator的完整類型集,否則定義需要進入頭文件。

只有當您知道所需的全部實例化(參數)時,才能將模板定義(實現)與聲明分開。編譯器不記得在一個.cpp(翻譯單元)中使用了哪些實例,並使用另一個.cpp中的代碼提供它們。

就像Andy提到的那樣,您似乎尋找的行爲以前被分配給C++ 03 export關鍵字,該關鍵字很少實現,並且結果是沒有希望的那麼有用,現在已經完全從標準。

如果你想走這條路(我正在寫一個類似的庫現在!),在extern關鍵字需要將class {}範圍之外去和.cpp文件需要顯式實例所需要的專業。

// header file 

class lexer { 
    public: 
    template<class InputIterator> 
    lexer(InputIterator i, InputIterator end); 
}; 

extern template lexer::lexer(foo::iterator, foo::iterator); 
extern template lexer::lexer(bar::iterator, bar::iterator); 

// source file 

template<class InputIterator > 
lexer::lexer(InputIterator i, InputIterator end) { 
    //make it work 
}; 

template lexer::lexer(foo::iterator, foo::iterator); 
template lexer::lexer(bar::iterator, bar::iterator);