2012-10-17 86 views
1

我們想專用基類的成員函數。但是,它不會編譯。有沒有人知道任何可以編譯的選擇?繼承的成員函數的模板特化

下面是一個例子

struct Base 
{ 
    template<typename T> 
    void Foo() 
    { 
     throw "Foo() is not defined for this type"; 
    } 
}; 

struct Derived : public Base 
{ 
    template<> 
    void Foo<int>() { cout << "Foo<int>()" << endl; } // compile error (cannot specialize members from a base class) 

    template<> 
    void Foo<double>() { cout << "Foo<double>()" << endl; } // compile error (cannot specialize members from a base class) 
}; 
+0

不會有多態行爲到基地,你不能使模板功能虛擬。 不知道你想達到什麼。 – CashCow

+0

我們試圖創建具有特定成員的工廠類,並且當我們不知道如何處理該方法未專用的類型時,我們想拋出一個異常。 我們希望在我們的例子中創建許多像Derived一樣的類。否則,我們不會有基類。 – Alex

+0

在編譯時失敗比在運行時拋出異常更好。 – CashCow

回答

0

這將編譯,除了調用Foo<char>():如果你想調用Foo<char>()

#include <iostream> 
#include <string> 
using namespace std; 

struct Base 
{ 
    template<typename T> 
    void Foo() 
    { 
     throw "Foo() is not defined for this type"; 
    } 
}; 

struct Derived : public Base 
{ 
    template<typename T> void Foo(); 
}; 

template<> 
void Derived::Foo<int>() { cout << "Foo<int>()" << endl; } 

template<> 
void Derived::Foo<double>() { cout << "Foo<double>()" << endl; } 

int main() 
{ 
    Derived derived; 

    // this is client code 
    derived.Foo<int>(); 
    derived.Foo<double>(); 
    derived.Foo<char>(); // this throws 
} 

- 或任何類型沒有特別的你專業 - 然後這工作。如果你想對所有類型的作品非專業的實現,那麼你需要添加的Foo()非專業的實施,以及:

template<typename T> 
void Derived::Foo() { cout << "generic" << endl; } 
+0

派生。富不扔。它只是不編譯(鏈接錯誤)。另外,我們將無法使用包含更多專業化的DerivedMore來擴展Derived類。 有沒有其他想法? – Alex

+0

@Alex:您可以簡單地爲Derived :: Foo添加一個默認實現:return base :: Foo ();' – dyp

+0

@DyP:我們可以,但這意味着我們必須將其添加到每個派生類型中。如果我有很多這些會發生什麼? – Alex

1

最後,我們解決了它使用重載。

這是基礎類的樣子

struct Base 
{ 
    template<typename T> 
    class OfType {} 

    template<typename T> 
    void Foo(OfType<T>) { static_assert(false, "Foo is not implemented for this type. Please look in the compiler error for more details."); } 
}; 

struct Derived : public Base 
{ 
    using Base::Foo; 

    void Foo(OfType<int>) { // here comes logic for ints } 
    void Foo(OfType<double>) { // here comes logic for doubles } 
}; 

下面是一個使用Foo()

template<typename S> 
class ClassThatUsesFoo 
{ 
    private: S s; 

    template<typename T> 
    void Bar(T item) 
    { 
     s.Foo(Base::OfType<T>()); // this is the code that uses Foo 
     DoSomeStuffWithItem(item); 
    } 
}; 

void main() 
{ 
    ClassThatUsesFoo<Derived> baz; 
    baz.Bar(12); // this will internally use Foo for ints 
    baz.Bar(12.0); // this will use Foo for doubles 
    baz.Bar("hello world"); // this will give a verbose compile error 
} 
+0

但你爲什麼要扔它?如果只是不編譯,那更好。 – CashCow

+0

你是對的。我會將其更改爲靜態斷言,或將其完全刪除。 無論如何,重載允許我創建派生類的層次結構。專業化不允許我做的事情。 – Alex

+0

順便說一句,編譯器錯誤比鏈接錯誤更好,它會告訴你在代碼中你使用了不良過載的地方,而不是簡單地說它不存在(你知道)。 其他幾點,主返回int不是void,並且當你拋出異常時,拋出從std :: exception派生的異常。 – CashCow

0

響應與亞歷克斯的討論(見的答案的評論的客戶端代碼示例John Dibling),這就是我的意思(SSCCE):

#include <iostream> 
using namespace std; 

struct Base 
{ 
    template<typename T> 
    void Foo() 
    { 
     //static_assert(false, "Foo() is not defined for this type"); 
     throw "Foo() is not defined for this type"; 
    } 
}; 
    // you can add as many specializations in Base as you like 
    template <> 
    void Base::Foo<char>() { cout << "Base::Foo<char>()" << endl; } 


struct Derived : public Base 
{ 
    // just provide a default implementation of Derived::Foo 
    // that redirects the call to the hidden Base::Foo 
    template < typename T > 
    void Foo() 
    { Base::Foo<T>(); } 
}; 
    // the specializations for Derived 
    template<> 
    void Derived::Foo<int>() { cout << "Foo<int>()" << endl; } 

    template<> 
    void Derived::Foo<double>() { cout << "Foo<double>()" << endl; } 


struct Derived_wo_specialization : public Base 
{ 
    /* nothing */ 
}; 


int main() 
{ 
    Derived d; 
    d.Foo<char>(); 
    d.Foo<double>(); 

    Derived_wo_specialization dws; 
    dws.Foo<char>(); 
    dws.Foo<double>(); 
}