2010-01-20 32 views
8

定義類聲明內部的模板類的成員函數與外部的區別?在類內部和外部定義的模板類的成員函數之間的區別

定義內:

template <typename T> 
class A 
{ 
public: 
    void method() 
    { 
     //... 
    } 
}; 

定義外:

template <typename T> 
class B 
{ 
public: 
    void method(); 
}; 

template <typename T> 
void B<T>::method() 
{ 
    //... 
} 

對於非模板類,這是內聯和非內聯方法之間的差別。模板類也是如此嗎?

我的大多數同事的默認設置是在類內提供定義,但我一直喜歡在類之外定義。我的意願是否合理?

編輯:請假設所有上述代碼都在類的頭文件中提供。

+0

我從來沒有見過任何引用表明在類聲明中定義方法主體使內聯方法。我錯過了什麼嗎? – Dathan 2010-01-20 17:53:15

+0

@Dathan: 請看這裏:http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.8 在這裏:http://msdn.microsoft.com/en-us /library/bw1hbe6y%28VS.80%29.aspx – Ben 2010-01-20 17:56:42

+3

@Dathan:你已經缺少C++標準的§9.3/ 2,它說:「一個成員函數可以在它的類定義中定義(8.4),其中它是一個內聯成員函數......「編輯:另請注意,這是一個類定義 - 類聲明是類似於:'class x;' – 2010-01-20 17:58:01

回答

2

是的,完全相同的是模板類如此。

模板類的方法定義通常首選內聯的原因是,對於模板,實例化模板時整個定義必須可見。

所以如果你把函數定義放在一些單獨的.cpp文件中,你會得到一個鏈接錯誤。 唯一的一般解決方案是通過在類內部或外部使用inline關鍵字定義函數來使函數內聯。但在任一情況下,它必須是可見的任何地方被調用的函數,這意味着它通常必須在相同的標頭,如在類定義。

+0

只是出於好奇,鏈接器錯誤現在普遍成立嗎?我在過去知道一些編譯器提供了不同的模板實例化選項,例如,SGI Irix CC編譯器默認爲鏈接時實例化,實際上似乎鼓勵將模板函數定義放在它們自己的.cpp文件中(即不在標題中,非內聯,不可見調用代碼,就像任何其他的非內聯函數定義一樣)只是想知道內聯模板函數定義是否已經從編譯器偏好變爲語言的要求 – Darryl 2010-01-20 18:37:18

+0

@Darryl,你正在描述extern模板。標準擴展,並不是所有的編譯器都支持它。新的標準C++ 1x增加了'extern'模板,儘管I bel即使它需要關鍵字。 – greyfade 2010-01-20 18:49:57

+0

模板在使用該特定實例的每個編譯單元中編譯,但它們是'弱'符號(gcc術語,我不知道標準是多麼標準),並且在多個編譯單元中定義了相同的符號不是一個鏈接錯誤。因此,不需要將「內聯」添加到模板函數/方法。另一種說法是'inline'是編譯器的一個提示,但它可以被編譯器忽略(但它會影響符號的創建方式,以便鏈接器不會抱怨雙重定義)。 – 2010-01-20 19:45:24

1

除了輸入更多信息之外,沒有區別。這包括template一下,inline具有參照類時多采用「精心製作」的名字。例如

template <typename T> class A { 
    A method(A a) { 
    // whatever 
    } 
}; 

template <typename T> inline A<T> A<T>::method(A a) { 
    // whatever 
} 

注意,當方法中定義指A<T>時,你總是可以省略模板參數列表<T>,只是使用A。在外部定義時,必須在返回類型和方法名稱中使用「完整」名稱(但不能在參數列表中)。

+0

你在這兩種情況下都使用了「方法」,如果函數體很大,這可能很糟糕。這就是我想要避免的。 – Ben 2010-01-20 18:14:41

+2

** inline **關鍵字與實際優化代碼較少有關,更多關於是否允許多個相同函數的定義。如果在頭文件中定義了一個函數(這對模板是不可避免的,或者在類聲明中定義了函數的情況),並且多個編譯單元包含該函數,那麼鏈接程序最終將最終得到多個(相同的)相同的功能/方法。 ** inline **關鍵字(它應該隱含在模板中)告訴鏈接器它是OK的,否則它會是鏈接器錯誤。 – UncleBens 2010-01-20 18:22:29

+0

關鍵是Ben用一個模板你沒有任何選擇。它必須內聯標記或模板不起作用。這是一些人不喜歡模板的原因之一。同樣值得注意的是,編譯器實際上並不需要內聯它可以做任何喜歡背後的事情。 – Goz 2010-01-20 18:23:26

0

我知道這個..我認爲它一定是一些什麼幫助完整的你?

defining a member function outside of its template 

這也不行提供模板類的這樣的一個成員函數的定義:

// This might be in a header file: 
template <typename T> 
class xyz { 
    void foo(); 
    }; 

// ...

// This might be later on in the header file: 
    void xyz<T>::foo() { 
// generic definition of foo() 
    } 

這是不對的幾個原因。所以是這樣的:

 void xyz<class T>::foo() { 
     // generic definition of foo() 
     } 

正確的定義需要template關鍵字和相同的模板參數,類模板的定義聲明。這樣得到:

 template <typename T> 
      void xyz<T>::foo() { 
      // generic definition of foo() 
       } 

注意,還有其他類型的模板指令,因爲成員模板等這樣的,每一個需要他們自己的形式。重要的是要知道你有什麼,所以你知道如何寫每種口味。這尤其是因爲一些編譯器的錯誤信息可能不清楚哪些是錯誤的。當然,獲得一本好的和最新的書。

如果你有一個模板中的嵌套成員模板:

template <typename T> 
     struct xyz { 
     // ... 
     template <typename U> 
     struct abc; 
     // ... 
     }; 

你是如何定義的xyz以外ABC?這不起作用:

 template <typename U> 
    struct xyz::abc<U> { // Nope 
     // ... 
    }; 

也沒有這樣的:

template <typename T, typename U> 
struct xyz<T>::abc<U> { // Nope 
// ... 
}; 

你將不得不這樣做:

 template <typename T> 
     template <typename U> 
      struct xyz<T>::abc { 
      // ... 
      }; 

注意它的...abc...abc<U>因爲ABC是 「主」模板。 IOWs,這不好:

//這裏不允許: 模板模板struct xyz :: abc {};

相關問題