2009-10-01 22 views
23

Czy można specjalizować poszczególnych członków klasy szablonów? Coś jak:Specjalizacja szablonowa poszczególnych członków?

template <typename T,bool B> 
struct X 
{ 
    void Specialized(); 
}; 

template <typename T> 
void X<T,true>::Specialized() 
{ 
    ... 
} 

template <typename T> 
void X<T,false>::Specialized() 
{ 
    ... 
} 

Oczywiście, ten kod jest nieprawidłowy.

+0

To nie do końca jasne, co masz na myśli. Czy masz na myśli wymuszenie, że parametr szablonu jest potomkiem określonego typu? Jak możesz w Javie z ? –

+1

@Alcon Specjalizując się w klasie szablonów, musi podać * inną * implementację dla całej klasy. Wydaje mi się, że chce dzielić wspólny kod pomiędzy specjalizacjami, z wyjątkiem kilku funkcji. – AraK

+0

Czy to pytanie powinno brzmieć "funkcja członka" zamiast "członek"? Aby nikt nie myślał, że chodzi o członków danych. –

Odpowiedz

3

To, co wymyślił, nie jest tak źle :)

//The generic template is by default 'flag == false' 
template <class Type, bool flag> 
struct something 
{ 
    void doSomething() 
    { 
     std::cout << "something. flag == false"; 
    } 
}; 

template <class Type> 
struct something<Type, true> : public something<Type, false> 
{ 
    void doSomething() // override original dosomething! 
    { 
     std::cout << "something. flag == true"; 
    } 
}; 

int main() 
{ 
    something<int, false> falseSomething; 
    something<int, true> trueSomething; 

    falseSomething.doSomething(); 
    trueSomething.doSomething(); 
} 
+5

Nie przeważasz, po prostu się ukrywasz. – curiousguy

26

Można tylko specjalizują się go wyraźnie, dostarczając wszystkie argumenty szablonu. Brak częściowej specjalizacji dla funkcji członkowskich szablonów klas jest dozwolony.

template <typename T,bool B> 
struct X 
{ 
    void Specialized(); 
}; 

// works 
template <> 
void X<int,true>::Specialized() 
{ 
    ... 
} 

Dzieło wokół jest wprowadzenie przeciążone funkcje, które mają korzyści z jeszcze będąc w tej samej klasie, a więc mają taki sam dostęp do członkowskich zmiennych, funkcji i środków

// "maps" a bool value to a struct type 
template<bool B> struct i2t { }; 

template <typename T,bool B> 
struct X 
{ 
    void Specialized() { SpecializedImpl(i2t<B>()); } 

private: 
    void SpecializedImpl(i2t<true>) { 
     // ... 
    } 

    void SpecializedImpl(i2t<false>) { 
     // ... 
    } 
}; 

Note że przechodząc do przeciążonych funkcji i przesuwając parametry szablonu do parametru funkcji, możesz dowolnie "wyspecjalizować" swoje funkcje, a także może je w razie potrzeby zmienić. Inną powszechną techniką jest odroczyć do szablonu klasy zdefiniowane oddzielnie

template<typename T, bool B> 
struct SpecializedImpl; 

template<typename T> 
struct SpecializedImpl<T, true> { 
    static void call() { 
    // ... 
    } 
}; 

template<typename T> 
struct SpecializedImpl<T, false> { 
    static void call() { 
    // ... 
    } 
}; 

template <typename T,bool B> 
struct X 
{ 
    void Specialized() { SpecializedImpl<T, B>::call(); } 
}; 

uważam, że zazwyczaj wymaga więcej kodu i uważam funkcja przeciążenia łatwiejsze w obsłudze, podczas gdy inni wolą odraczać klasa szablonu sposób. W końcu to kwestia gustu. W takim przypadku możesz umieścić ten inny szablon wewnątrz X również jako szablon zagnieżdżony - w innych przypadkach, w których jawnie specjalizujesz się zamiast tylko częściowo, nie możesz tego zrobić, ponieważ możesz umieszczać jawne specjalizacje tylko w obszarze przestrzeni nazw, nie do zakresu klasy.

Można również stworzyć taki SpecializedImpl szablon tylko dla celów funkcji przeciążenia (to wtedy działa podobnie do naszego i2t z wcześniej), co ilustruje poniższy wariant pokazuje, który opuszcza pierwszy parametr zmienny też (tak można nazwać to z innych rodzaje - nie tylko z parametrami szablonu bieżącej instancji'S)

template <typename T,bool B> 
struct X 
{ 
private: 
    // maps a type and non-type parameter to a struct type 
    template<typename T, bool B> 
    struct SpecializedImpl { }; 

public: 
    void Specialized() { Specialized(SpecializedImpl<T, B>()); } 

private: 
    template<typename U> 
    void Specialized(SpecializedImpl<U, true>) { 
     // ... 
    } 

    template<typename U> 
    void Specialized(SpecializedImpl<U, false>) { 
     // ... 
    } 
}; 

myślę czasami, odroczenie na inny szablon jest lepiej (jeśli chodzi o takich przypadkach jak tablice i wskaźniki, przeciążenia może trudne i tylko przekierowanie do szablonu klasy było mi wtedy łatwiej), a czasami po prostu przeciążenie w szablonie jest lepsze - zwłaszcza jeśli naprawdę argumenty funkcji Ward i jeśli dotkniesz zmiennych członków klasy.

+0

+1 Ładne, eleganckie rozwiązania na moich oczach. – AraK

+0

dziękuję, doceniłem :) –

+0

Teraz, gdy C++ 11 jest obecnie, powinno to używać 'std :: integral_constant' mnie myśli. Zmienilabym się, ale to naprawdę kłopotliwe w mobilnym widoku na iPodzie Touch ... – Xeo