2016-05-30 5 views
1

Das folgende grundlegende Beispiel der partiellen Template-Klasse Spezialisierung, genommen von this wiki page:Template-Klasse teilweise Spezialisierung Syntax

template <typename Key, typename Value> 
class KeyValuePair { /* something generic */ }; 

template <typename Key> 
class KeyValuePair<Key, bool> { /* something specific to Value=bool */ }; 

KeyValuePair<int> kvpi; 

erzeugt einen Compiler-Fehler:

prog.cpp:10:17: error: wrong number of template arguments (1, should be 2) KeyValuePair<int> kvpi; 

Warum? Was mache ich falsch ? Wie eine partielle Template-Klassenspezialisierung deklariert und instanziiert werden soll?

Ich erwarte, dass die Variable kvpi eine teilweise spezialisierte Vorlagenklasseninstanz vom Typ KeyValuePair<int,bool> ist.

+0

Was Sie erwarten 'Value' in' KeyValuePair 'zu sein? – TartanLlama

+0

@TartanLlama: In 'KeyValuePair ' erwarte ich, dass 'Value' 'bool' ist, aber ich habe offensichtlich die Teilspezialisierung nicht richtig definiert, um dies zu tun. – shrike

+2

@shrike Die teilweise Spezialisierung funktioniert nicht so, wie Sie es erwarten. Sie müssen den Schlüssel- und den Werttyp angeben. Nur wenn der Werttyp bool ist, wird die Implementierung der spezialisierten Klasse ausgewählt, für alle anderen Typen wird die erste Implementierung verwendet. – Arunmu

Antwort

3

Sie scheinen mit verwirrenden Teil-Spezialisierung zu sein Standardschablonenargumente. Es scheint weiterhin, dass Sie beides brauchen (aus Gründen, die nicht erwähnt werden, aber nicht wirklich wichtig sind). Obwohl nicht ganz intuitiv, es kann wie folgt erreicht werden:

#include <iostream> 

template <typename Key, typename Value = bool> 
class KeyValuePair 
{ 
public: 
    KeyValuePair() 
    { 
     std::cout << __PRETTY_FUNCTION__ << ':' << "original\n"; 
    } 
}; 

template <typename Key> 
class KeyValuePair<Key, bool> 
{ 
public: 
    KeyValuePair() 
    { 
     std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n"; 
    } 
}; 


int main() 
{ 
    KeyValuePair<int,int> kvp1; 
    KeyValuePair<int> kvp2; 
} 

Ausgabe

KeyValuePair<int, int>::KeyValuePair() [Key = int, Value = int]:original 
KeyValuePair<int, bool>::KeyValuePair() [Key = int, Value = bool]:specialized 

Das verwirrende Teil zu einigen ist die Standard-Argument-Spezifikation, sondern eine Vorlage, die folgt, die nie wirklich sehen Erfüllung mit diesem Standard-arg wegen der späteren Spezialisierung. In solchen Fällen bevorzuge ich die Forward-Deklaration der Vorlage mit ihrer Standardargumentliste. Zumindest für mich macht es das Lesen etwas leichter. Sie können sich (oder auch nicht) dazu entschließen, dasselbe zu tun, wenn Sie das Gefühl haben, dass es Klarheit bietet. So etwas wie:

template <typename Key, typename Value = bool> 
class KeyValuePair; 

template <typename Key, typename Value> 
class KeyValuePair 
{ 
public: 
    KeyValuePair() 
    { 
     std::cout << __PRETTY_FUNCTION__ << ':' << "original\n"; 
    } 
}; 

template <typename Key> 
class KeyValuePair<Key, bool> 
{ 
public: 
    KeyValuePair() 
    { 
     std::cout << __PRETTY_FUNCTION__ << ':' << "specialized\n"; 
    } 
}; 
+0

Ich habe tatsächlich teilweise Spezialisierung und Standardparametrisierung verwechselt; und ich brauche beide, genau wie dein Ausschnitt es illustriert. Danke für deine Antwort. – shrike

2

Sie definieren Ihre teilweise Spezialisierung korrekt, aber die Vorlage erwartet 2 Argument und Sie bieten nur eine.

Sie Standardargument verwenden:

template <typename Key, typename Value = bool> 
class KeyValuePair {}; 

KeyValuePair<int> kvpi; 

zu ermöglichen, und Sie können Ihre Teil-Spezialisierung halten, wenn

benötigt
template <typename Key> 
class KeyValuePair<Key, bool> { /* something specific to Value=bool */ }; 
+0

OK, verstanden, ich verwirrte teilweise Spezialisierung und Standardparameter; eigentlich brauche ich beides. Danke für das Zeigen, was falsch war. – shrike

+0

@ Jarod42: Danke für Ihre Antwort, ich brauche zwar einen Standardparameter, aber ich brauche auch eine Teilspezialisierung (dh: die Implementierung von KeyValuePair muss anders sein, wenn sie nur mit dem Parameter Key instanziiert wird); füge es deinem Snippet hinzu und ich akzeptiere deine Antwort. – shrike

3

Die teilweise Template-Spezialisierung erlaubt es Ihnen nicht, einen Template-Parameter zu vergessen. Sie müssen schreiben:

KeyValuePair<int, bool> kvpib; 

und die korrekte Spezialisierung wird verwendet.

Aber Sie können die Vererbung verwenden, um zu erreichen, was Sie wollen:

template <typename Key> 
class KeyBoolPair : public KeyValuePair<Key, bool> {}; 

KeyBoolPair<int> kbpi; 

oder wenn Sie C++ 11 oder höher:

template <typename Key> 
using KeyBoolPairBis = KeyValuePair<Key, bool>; 

KeyBoolPairBis<int> kbpbi; 

Beispiel: http://coliru.stacked-crooked.com/a/5095fc5c358d291a

+0

Nähte, um meine Bedürfnisse auch zu beantworten; entspricht dies der Verwendung von Teilspezialisierungen in Verbindung mit Standardparametern (wie in der Antwort von WhozCraig)? – shrike

+0

Für mich ist es nicht gleichwertig: Entwickler können 'KeyValuePair' definitiv nicht mit nur einem Template-Parameter verwenden; Sie müssen eine "andere" Klasse benutzen. Diese andere Klasse basiert (Vererbung) oder ein Alias ​​('using' Schlüsselwort) von' KeyValuePair'. Und in beiden Fällen müssen Sie spezialisierte Vorlage (dh, haben Sie Vorlage Klasse KeyValuePair .... '). Persönlich bevorzuge ich 'using' – Garf365

+0

ok, habe ich nicht bemerkt, dass Sie den Vorlagenklassennamen änderten, der tatsächlich obligatorisch ist; dann wird die Lösung mit dem Standardparameter meinen Bedürfnissen am besten entsprechen, da sich der Name nicht ändert. trotzdem danke. – shrike