Ogni specializzazione introduce un tipo di dati completamente nuovo (o un modello completamente nuovo, se la specializzazione è solo parziale). Dalla standard (C++ 11):
(§14.5.5/2) Ciascun modello di classe parziale specializzazione è un modello distinto e definizioni devono essere previsti per i membri di un modello di specializzazione parziale (14.5.5.3).
E:
(§14.5.5.3/1) [...] I membri del modello di classe di specializzazione parziale sono estranei ai membri del modello primario. Devono essere definiti membri di specializzazione parziale del modello di classe che sono utilizzati in un modo che richiede una definizione; le definizioni dei membri del modello primario non vengono mai utilizzate come definizioni per i membri di una specializzazione parziale del modello di classe. [...]
È possibile che questo sia previsto nel contesto di parziali specializzazioni, ma vale anche per le specializzazioni esplicite (come nel tuo caso) e, anche se lo standard non dice molto chiaramente.
Si noti inoltre che è necessario non solo dichiarare tutte le funzioni membro che si desidera in una specializzazione, ma è necessario definirli, anche (qui, lo standard è molto chiara anche su specializzazioni esplicite):
(14.7.3/5) Un membro di una classe esplicitamente specializzata non è istanziato implicitamente dalla dichiarazione membro del modello di classe; al contrario, il membro della specializzazione del modello di classe deve essere definito esplicitamente se la sua definizione è richiesta. In questo caso, la definizione della specializzazione esplicita del modello di classe deve essere nello scope nel punto in cui è definito il membro. La definizione di una classe esplicitamente specializzata non è correlata alla definizione di una specializzazione generata. Cioè, i suoi membri non devono avere gli stessi nomi, tipi, ecc. Come membri di una specializzazione generata. [...]
Così, in effetti, A<int>
avrà solo method2()
, e A<float>
avrà solo method1()
come membro. Inoltre, se si introducesse method1()
nella specializzazione A<int>
, non è necessario avere lo stesso tipo di argomento o il tipo restituito come A<float>::method1()
.
Vedere la risposta di @ aschepler per possibili modi per evitare di dover riscrivere la definizione del modello per il caso int
.
@Fellowshee Sì, puoi farlo. In tal caso, non dichiarare un nuovo 'template <> struct A {...};', ma semplicemente dichiarare (e definire) il metodo che si desidera specializzare: 'A :: method1() {.. .}; 'al di fuori della definizione del modello di classe. –
jogojapan
Interessante, una dichiarazione fuori classe e la definizione di una funzione che non è menzionata all'interno della classe è considerata legale? – johnbakers
@Fellowshee Oh scusa, pensavo che avessi bisogno di una specializzazione di 'method1' per il caso' int'. Se hai davvero bisogno di aggiungere un metodo completamente nuovo 'method2' solo per il caso' int', allora in effetti dovrai riscrivere l'intero template per 'int'. A seconda della situazione, potrebbe essere meglio aggiungere 'method2' alla definizione del template primario ma lasciarlo indefinito (o lanciare un'eccezione, o inserire un' static_asssert (false, "non implementato"); '(il quest'ultimo funziona solo in C++ 11)). In questo modo potresti specializzare 'method2' per il caso' int' senza dover riscrivere l'intero modello. – jogojapan