2011-07-15 72 views
7

我有一個模板專業化問題,我想了解。我正在使用Visual C++ 10.0(2010)。我有這樣一個類:模板專業化鏈接失敗

class VariableManager 
{ 
public: 

    template<typename VarT> 
     VarT get(std::string const& name) const 
     { 
        // Some code... 
     } 

    // This method supposed to be fully evaluated, linkable method. 
    template<> 
     std::string get<std::string>(std::string const& name) const; 

private: 
    std::map<std::string, boost::any> mVariables; 
}; 

從理論上講,因爲我的專業「獲取」的方法,連接器應該能夠從一個目標文件回升。相反,我得到的鏈接未解決的引用錯誤,如果我把源文件的方法:

template<> 
    std::string VariableManager::get<std::string>(std::string const& name) const 
      { 
       // Doing something... 
      } 

如果我把這個方法在頭文件內聯,構建去就好了。我不明白,模板功能,因爲這:

 template<typename VarT> 
      VarT get(std::string const& name) const; 

應放置在頭部,因爲編譯器將不能夠根據調用代碼,專門的模板,但完全專業化的情況下,它是類「實現,因此專用模板方法應該已經作爲公共符號存在。有人可以提出這個問題嗎?

回答

10

你的分析是正確的 - 即有明確的值指定的任何模板參數的明確專門的函數模板提供了一個功能完整的定義。

如果您已將包含顯式專業化定義的相應.cpp文件正確包含到您的項目中,那麼VC++不應引發鏈接器錯誤。對於標準合規性,請注意,您必須在封閉類的之外申報專業。標準禁止在封閉類中聲明明確的特化(其他編譯器會拒絕你的代碼)。因此改變頭文件來聲明這樣的專業化,而不是

class VariableManager 
{ 
public: 

    template<typename VarT> 
     VarT get(std::string const& name) const 
     { 
        // Some code... 
     } 

private: 
    std::map<std::string, boost::any> mVariables; 
}; 

// This method supposed to be fully evaluated, linkable method. 
template<> 
std::string VariableManager::get<std::string>(std::string const& name) const; 

讓我也注意到,你不能叫get<std::string>類的身體內。這是因爲任何這樣的調用都不會看到明確的特化聲明,因此會嘗試從模板定義中實例化函數。該標準使這種代碼不合格,不需要診斷。

+0

有趣,但似乎標準合規問題是問題所在。我刪除了課堂上的聲明,並按照您的建議進行了專業化聲明,並且鏈接器沒有任何問題。應該記住,專業化必須在課堂範圍之外宣佈。感謝您的親切幫助! – progician

+0

對我來說,找到你的答案真是太幸運了。對於我來說,如果我將模板特化放在類中,而鏈接器無法找到它,那麼編譯器的工作仍然是一個謎。但是,你絕對保存了我的一天! – Nipheris

0

專門化模板不會強制編譯器實例化它(我認爲GCC雖然);您仍然需要明確告訴編譯器實際實例化模板。您可以使用顯式模板實例化來完成此操作。基本上,只要添加這個源文件中:

template std::string VariableManager::get(const std::string& name) const; 
+0

這是錯誤的。他專業化,所以他不需要也不想實例化模板 –

+1

litb是對的,這確實是錯誤的,但我會在這裏留下我的答案,以便其他人可以看到它也是錯的 –

0

方法開始template<>仍然被認爲是template專業化方法。所以你必須把頭文件放進去。

如果你想要把它變成一個實現文件,那麼你必須超載它。

class VariableManager 
{ 
//... 
    VarT get(std::string const& name) const 
    {} 

    std::string get(std::string const& name) const; //overloading not specialization 
}; 
+0

不,你不需要。請參閱reko的答案。我不確定你想通過「模板專業化方法」來達到什麼目的。 –

+0

(**但是**我會推薦超過專業化_anyday_!) –

+0

@Tomalak,OP正在嘗試專門化問題中的'template'方法'get'。我的答案是應該在頭文件中聲明專門的方法。你能指定更多,什麼是錯的? – iammilind