2010-09-22 13 views
6

Hallo!C++ - Single-Template-Spezialisierung mit mehreren Template-Parametern

Ich möchte nur eine von zwei Vorlagentypen spezialisieren. Z.B. template <typename A, typename B> class X sollte eine spezielle Implementierung für eine einzelne Funktion haben X<float, sometype>::someFunc().

Beispielcode:

main.h:

#include <iostream> 

template <typename F, typename I> 
class B 
{ 
public: 
    void someFunc() 
    { 
     std::cout << "normal" << std::endl; 
    }; 

    void someFuncNotSpecial() 
    { 
     std::cout << "normal" << std::endl; 
    }; 
}; 

template <typename I> 
void B<float, I>::someFunc(); 

main.cpp:

#include <iostream> 
#include "main.h" 

using namespace std; 

template <typename I> 
void B<float, I>::someFunc() 
{ 
    cout << "special" << endl; 
} 

int main(int argc, char *argv[]) 
{ 
    B<int, int> b1; 
    b1.someFunc(); 
    b1.someFuncNotSpecial(); 

    B<float, int> b2; 
    b2.someFunc(); 
    b2.someFuncNotSpecial(); 
} 

Compilation nicht für class B. Stimmt es, dass dies in C++ nicht möglich ist? Was wäre die beste Problemumgehung?

[Bearbeiten]

template <float, typename I> void B<float, I>::someFunc(); führt zu main.h: 26: Fehler: 'schweben' ist kein gültiger Typ für einen konstanten Template-Parameter

template <typename I> void B<float, I>::someFunc(); zu main.h führt: 27: Fehler: ungültige Verwendung des unvollständigen Typs 'Klasse B'

Und ich benutze gcc.

[Bearbeiten]

Ich will nicht die ganze Klasse spezialisieren, da es andere Funktionen, die nicht über eine Spezialisierung haben.

+0

Ist die Klassenvorlage A mit Ihrer Frage verknüpft? – Doug

+0

Ich dachte, es würde die Frage leichter verständlich machen. Ich werde es entfernen. – tauran

+0

Dies wurde hunderte Male auf stackoverflow gefragt :) Ich denke, einige von uns könnten eine echte Vorlage FAQ mit solchen Fragen einrichten. Die Leute können die FAQ überprüfen, um zu sehen, ob ihre Frage beantwortet wird, anstatt nach einem Betrogenen suchen zu müssen. –

Antwort

16

Sie haben, um eine partielle Spezialisierung der Klassenvorlage B:

template <typename I> 
class B<float, I> 
{ 
public: 
    void someFunc(); 
}; 

template <typename I> 
void B<float, I>::someFunc() 
{ 
    ... 
} 

Sie können auch festlegen, nur someFunc in der Spezialisierung.

Jedoch wenn Sie nur eine Funktion spezialisieren möchten, und keine Klasse e. G.

template <typename F, typename I> 
void someFunc(F f, I i) { someFuncImpl::act(f, i); } 

template <typename F, typename I> 
struct someFuncImpl { static void act(F f, I i) { ... } }; 

// Partial specialization 
template <typename I> 
struct someFuncImpl<float, I> { static void act(float f, I i) { ... } }; 

Aber Sie können eine Funktionsvorlage nicht ohne diesen Trick spezialisieren.

+1

Das konnte man nicht wissen. Aber in meinem Anwendungsfall gibt es viele andere Funktionen, die keine Spezialisierung haben. Mit diesem Ansatz müsste ich alle diese Funktionen verdoppeln. – tauran

+1

@tauran: Sie können keine partiellen Spezialisierungen für Funktionsvorlagen bereitstellen. Nur für Klassenvorlagen, und Sie müssen die Definition für die gesamte Klasse erneut angeben. Lebe damit oder sieh dir die aktualisierte Antwort an. –

+0

Könnten Sie bitte eine weitere Sache in Taurans Code ansprechen? Es gibt 'template void B :: someFunc();' am Ende von 'main.h'. Ich glaube, Tauran möchte erklären, dass irgendwo in einer anderen Kompilierungseinheit eine Spezialisierung definiert ist. Sind exportierte Vorlagen nicht erforderlich? Wenn die Spezialisierung gemeint ist, um in allen Kompilationseinheiten sichtbar zu sein, ist 'main.h' enthalten, muss es nicht in der Kopfzeile sein? –

5

Although you can totally specialize member functions of a class template, you cannot _partially specialize member functions. - Andrei Alexandrescu

Teil Klasse Spezialisierung wird von den anderen Plakaten erklärt.

Sie können jedoch die Verwendung Überlastung:

template <class T, class U> T fun(U obj); // primary template 
template <class U> void Fun<void, U>(U obj); // illegal pertial 
// specialization 
template <class T> T fun (Window obj); // legal (overloading) 

Wenn Sie tief in diese gehen wollen, können Sie über dieses Thema in der Tiefe in "Moderne C++ Design" von A. Alexandrescu lesen.

+0

+1 für den Abruf von Template-Überladungen. Dies ist ein Werkzeug, über das ich selten nachdenke, das aber in manchen Situationen funktioniert. –

0

Lösung 1. Verschieben Sie alle Implementierungen in eine Basisklasse wie B_Base. Dann spezialisieren Sie sich auf float, um das someFunc zu überschreiben. wie unten

template <typename F, typename I> 
    class B : B_Base<F, I> 
    { 
    } 

    template <typename I> 
    class B<float, I> : B_Base<flat, I> 
    { 
    public: 
     void someFunc() {....} 
    }; 

Lösung 2. Funktion Lastbetrieb, setzen Schwimmer als Ein- oder boost :: is_same zu versenden.leider funktionieren Sie someFunc hat keinen Parameter. Daher muss die Schnittstelle geändert werden.