我嘗試創建與像可變參數一個EXTERN的模板:與可變參數的extern模板不編譯
extern template<typename... XS> void log(XS... xs);
但是GCC 7.2不編譯它,並顯示錯誤:
error: expected unqualified-id before ‘<’ token
我檢查了C++ 11中的gcc狀態,並且extern模板應該可以工作,不是嗎?
我嘗試創建與像可變參數一個EXTERN的模板:與可變參數的extern模板不編譯
extern template<typename... XS> void log(XS... xs);
但是GCC 7.2不編譯它,並顯示錯誤:
error: expected unqualified-id before ‘<’ token
我檢查了C++ 11中的gcc狀態,並且extern模板應該可以工作,不是嗎?
extern
關鍵字做的事情與你的期望不同 - 當然,如果我理解正確,你期望的是什麼。
extern
關鍵字應用於顯式實例化的模板,它可以防止編譯器在處理某個翻譯單元時隱式生成該模板的代碼。每一段中的C++ 11標準的14.7.2/2:
There are two forms of explicit instantiation: an explicit instantiation definition and an explicit instantiation declaration. An explicit instantiation declaration begins with the
extern
keyword.
沒有extern
關鍵字,編譯器會生成在包含調用log(double, int)
每個翻譯單元,用於(比方說)log(double, int)
代碼,和該代碼 - 對所有翻譯單元來說都應該是相同的 - 最終會被鏈接器合併(鏈接器基本上會丟棄所有的重複項並只保留一個)。
的extern
關鍵字告訴編譯器把你從這些廢物的編譯時間:「相信我,別人會在其他地方實例化這個模板 - 你不需要做現在」。 但是,這個承諾必須履行。
因此,舉例來說,如果你有這樣的主模板:
template<typename... Xs> void log(Xs... xs);
並且聲明這顯式實例:
extern template void log(int, double);
比你必須有一些翻譯單元對應的顯式實例:
template void log(int, double)
否則,編譯器將永遠不會產生代碼log<int, double>(int, double)
,鏈接器會抱怨未定義的引用。
是的,你得到它rigth。我的意圖是在頭文件中聲明extern,然後在.cpp文件中定義。我發現這是不允許的,因爲它應該有明確的參數。 – Zhen
@ Zhen:是的,不幸的是,允許您將模板定義放入'.cpp'文件的唯一情況是您爲所有模板實例化創建了一個顯式實例化,否則這些實例化將以隱式方式生成。 C++ 03有一個名爲'export'的關鍵字來解決這個問題,但是對於編譯器供應商來說它很難支持它(只有基於EDG的編譯器),所以它在C++ 11中被移除了 –
@AndyProwl--在實施它之後,EDG提出了刪除它的建議。 –