2011-11-19 154 views
1

我想爲模板類中的成員函數有幾個不同的函數定義。事情是這樣的:專用模板成員函數?

template <typename T> 
class MyClass 
{ 
    void Foo(); 
    T val; 

    //other functionality and data 
}; 

    //handles all types 
template <typename T> 
void MyClass<T>::Foo() 
{ 
    return val; 
} 

    //handles a special type in a different way 
template <> 
void MyClass<float>::Foo() 
{ 
    return val + 5.0f; 
} 

我試圖實現與上述這一點,並得到一個鏈接錯誤爲每個特殊類型的我嘗試顯式實例。鏈接器錯誤提到該函數已經被定義過。也許我在錯誤的地方看,但我找不到任何資源來幫助我找出這個問題:(

問:這是可能的嗎?如果是這樣,你如何做到這一點,爲什麼它的工作?

謝謝!

+0

我剛剛粘貼您的定義在頭文件中,這是我從兩個不同的源文件包括在內;在兩個源文件中,我爲專門和非專用模板類的實例都調用了Foo()方法。一切正常,用g ++ - 4.4.3。你能否提供一些關於鏈接器錯誤和項目結構的更多細節? – misberner

+1

這應該工作;你的問題必須在別處。確保您熟悉常規模板機制以及標題和鏈接問題。 –

+1

[適用於我](https://ideone.com/IpHd0)。 –

回答

3

這是我經常使用的解決方法。正如之前所說,你必須專門化完整的模板。這個想法是讓你想要專門化某個結構的靜態成員的方法(爲了封裝的原因,它應該是嵌套的和私有的)。就像這樣:

template< typename T > 
class MyClass { 

    struct PerformFoo { 
     static void doFoo() { 
      std::cout << "Foo for general type" << std::endl;; 
     } 
    }; 

public: 
    void Foo() { 
     PerformFoo::doFoo(); 
    } 
}; 

template<> 
struct MyClass<float>::PerformFoo { 
    static void doFoo() { 
     std::cout << "Foo for float" << std::endl;; 
    } 
}; 

現在在你的主,代碼

MyClass<int> myInt; 
myInt.Foo(); 

MyClass<float> myFloat; 
myFloat.Foo(); 

打印在終端上

Foo for general type 
Foo for float 

。順便說一句:這不涉及現代編譯器的任何性能損失。希望這可以幫助你。

+0

謝謝,這絕對解決了這個問題。所以這個原因起作用的原因是因爲我需要在使用之前完全專注於該函數調用。通過使它成爲我的類可以專門化的結構的靜態成員,可以確保在調用之前該結構本身將專用化,對嗎?再次感謝您的幫助。 – KiraBox

+0

對不起,延遲迴答。我不知道這是否是'正確的'解釋,因爲我不是C++編譯器實現方面的專家。我只知道這是有效的,而且這個技巧用於一個科學項目中,我正在努力研究:) – Sh4pe

-1

這是不可能的。當你專注一個模板,必須專門整個模板,在這種情況下意味着整個類。

您可以FOO裏面的一個模板函數模板類,與你所要求的不完全一樣,但它可能會滿足你的需求。

更新:

template<typename T> class Foo { 
public: 
    template<typename R> void foo() {printf("This is foo\n");} 
    template<> void foo<float>() {printf("This is foo<float>\n");} 
}; 

或者:

template<typename T> class Foo { 
public: 
    template<typename R> void foo() {printf("This is foo\n");} 
    //template<> void foo<float>() {printf("This is foo<float>\n");} 
}; 

template<> template<> void Foo<float>::foo<float>() { 
    printf("This is foo<float>\n"); 
} 

連同:

int main(int argc,char * argv[]) 
{ 
    Foo<int> iFoo; 
    iFoo.foo<int>(); 

    Foo<float> fFoo; 
    fFoo.foo<float>(); 

    return 0; 
} 

產生:

This is foo 
This is foo<float> 

調用foo的語法有點尷尬。

+0

我以爲是一樣的,但一個簡單的實驗(使用g ++ 4.4.3)剛剛證明我錯了。 – misberner

0

我試着實現這個如上所述,並獲得每個特殊類型的鏈接器錯誤,我嘗試顯式實例化。

這是什麼意思?如果明確地專門化模板,則不能再爲相同的模板參數顯式實例化它。顯式專業化的全部目的是防止它的實例化(這是一個生成的專業化)有利於你的明確的專業化

所以你的描述對我來說沒有意義。請記住,如果要隱式實例化它們,則需要將頭文件的模板和成員函數的定義放在頭文件中,而不要放在.cpp文件中。而且需要向所有使用模板和參數的人聲明明確的專業化。

// put this specialization into the header, for everyone to see 
template <> void MyClass<float>::Foo(); 
1

通過將專門的成員函數定義爲內聯函數,您將擺脫抱怨在其他地方定義的專用成員函數的鏈接錯誤。

//handles a special type in a different way 
template <> 
inline void 
MyClass<float>::Foo() 
{ 
    return val + 5.0f; 
} 

原因是一個專門的函數不再是函數模板,而是一個具體的函數。因此,編譯包含此頭文件的源文件時會多次編譯,這就是爲什麼您會收到「已定義」錯誤。

另一種解決方法是將專用函數的實現從頭文件中移出並放入源文件中,同時在頭文件中聲明專用函數。需要注意的是專業的成員函數的聲明必須留在類定義之外:

/// Declare the specialized function in the header file but outside the 
/// class definition. 
template <> void MyClass<float>::Foo() 

/// Define the specialized function in .cpp file: 
template <> 
void 
MyClass<float>::Foo() 
{ 
    return val + 5.0f; 
}