2012-04-23 3 views
16

Gegeben:Teil Spezialisierung eines Verfahrens in einer Templat-Klasse

struct A 
{ 
    virtual bool what() = 0; 
}; 

template<typename T, typename Q> 
struct B : public A 
{ 
    virtual bool what(); 
}; 

ich teilweise wollen spezialisieren what wie:

template<typename T, typename Q> 
bool B<T, Q>::what() 
{ 
    return true; 
} 

template<typename Q> 
bool B<float, Q>::what() 
{ 
    return false; 
} 

Aber es scheint, dass dies nicht möglich ist (ist es in C++ 11) so habe ich versucht SFINAE:

template<typename T> 
typename std::enable_if<std::is_same<T, float>::value, bool>::type B<T>::what() 
{ 
    return true; 
} 

template<typename T> 
typename std::enable_if<!std::is_same<T, float>::value, bool>::type B<T>::what() 
{ 
    return false; 
} 

Dies auch nicht funktioniert, ich habe keine Ahnung, warum, wenn jemand tut? So fand ich this thread und endete mit:

template<typename T, typename Q> 
struct B : public A 
{ 
    virtual bool what() 
    { 
     return whatimpl(std::is_same<T, float>()); 
    } 

    bool whatimpl(std::false_type) 
    { 
     return false; 
    } 

    bool whatimpl(std::true_type) 
    { 
     return true; 
    } 
}; 

Diese endgültige Lösung funktioniert, aber warum nicht die enable_if Technik? Ich bin auch sehr offen für Vorschläge einer saubereren Antwort, die ich noch nicht erlebt habe.

ich vereinfachte meine Beispiele so viel wie möglich - in meinem realen Anwendungsfall what() nicht WHAT genannt wird und was tatsächlich ein gutes Stück Arbeit, und ich werde will auf einem benutzerdefinierten Typ zu ‚spezialisieren‘, nicht float.

+1

@Nawaz Ich habe das erkannt, aber das ist nur ein vereinfachter Fall, um zu zeigen, was ich versuche zu tun :) Lesen Sie die letzte Zeile in der Post. – David

+0

_what_ ist keine Template-Methode, um A :: what() zu überschreiben, sollte es eine einzige Nicht-Template-Methode der Klassenvorlage B sein. Sie können keine Nicht-Template-Methode spezialisieren, weder mit enable_if noch mit irgendeiner anderen Technik. Sie können jedoch die gesamte Klasse B spezialisieren – user396672

+0

@ user396672 Dann warum funktioniert das (vollständige Spezialisierung anstelle von partiellen): 'Vorlage <> bool B :: was() { { Rückgabe false; } ' – David

Antwort

7

Teil Spezialisierung ausdrücklich nur von der Norm erlaubt ist nur explizite Spezialisierung ist erlaubt.

14,7 (3) sagt:

Eine explizite Spezialisierung kann für eine Funktionsvorlage, eine Klassenvorlage, ein Mitglied einer Klasse Vorlage oder ein Mitglied Vorlage deklariert werden. Eine explizite Spezialisierungserklärung wird durch Vorlage <> eingeführt.

So jede Definition, beginnend mit

template<typename T> 

ist nicht erlaubt Syntax für Mitglied der Template-Spezialisierung Klasse.

[Bearbeiten]

Was SFINAE Versuch scheiterte, weil tatsächlich es weder Überlastungen noch Spezialisierungen sind hier (SFINAE arbeitet, während eine Reihe von Kandidaten-Funktionen für die Überladungsauflösung definieren oder während richtige Spezialisierung wählen). was() als einzige Methode der Klasse Template deklariert und sollte eine einheitliche Definition haben, und diese Definition sollte eine Form haben:

template<typename T, typename Q> 
B<T,Q>:: bool what(){...} 

oder auch für bestimmte Instanziierung der Klasse B explizit sein kann spezialisiert:

template<> 
B<SomeParticularTypeT,SomeParticularTypeTypeQ>:: bool what(){...} 

Alle anderen Formen sind syntaktisch ungültig, daher kann SFINAE nicht helfen.

+0

Danke, das erklärt den ersten gescheiterten Versuch. Irgendein Einblick in den SFINAE Versuch? – David

+0

@Dave: SFINAE Abkürzung "SPECIALIZATION Fehler ist kein Fehler", so ist es nur eine bestimmte Technik für _spezialisierung_. Beginnend mit der Vorlage ... haben Sie versucht, eine Methode der Klassenvorlage nur mit etwas komplizierterer Art zu spezialisieren. – user396672

+0

@Dave :: ... oder Vorlage kann Methode _definition_ für Klassenvorlage B starten, aber in diesem Fall ist es überhaupt keine Spezialisierung und SFINAE funktioniert auch nicht. – user396672

2

Warum es nicht nur zu ..

ändern für Klassen-Templates (siehe 14.5.5 Klasse Vorlage partielle Spezialisierungen)

für Mitglieder der Klasse template

template<typename T, typename Q> 
struct B : public A 
{ 
    bool what() 
    { 
     return false; //Or whatever the default is... 
    } 
}; 

template<typename Q> 
struct B<float, Q> : public A 
{ 
    bool what() 
    { 
     return true; 
    } 
}; 
+3

Weil B ist eine riesige Klasse und ich möchte nicht eine riesige Klasse 15 Mal für jede Spezialisierung von 'what()' – David

+0

@Dave: ... kopieren, obwohl Sie von der Zwischenriesenklasse erben können, die nur was () überschreiben in der letzten Klasse. – user396672

+0

@ user396672 Ich konnte das nur tun, wenn ich eine zusätzliche Klasse in der Vererbung hinzugefügt habe - beachte, dass A nicht auf Vorlagen basiert, so dass die Funktionalität von B wirklich nicht dort eingefügt werden konnte. Die Extra-Klasse müsste templatiert werden und zwischen A und B gehen. Das könnte als eine andere Antwort geschrieben werden, um auf andere Techniken zu reagieren, um das zu handhaben. – David