2017-02-17 2 views
2

Ich habe die folgenden Klassen:Wie kann ich spezialisieren/eine Template-Funktion für einen Templat-Typ überlasten

template <> 
container<int>::container() { 
    std::cout << "int constructor" << std::endl; 
} 
:

template <class... T> 
class thing {}; 

template <class T> 
class container { 
    public: 
     container() { 
      std::cout << "normal constructor" << std::endl; 
     } 
}; 

ich eine volle Spezialisierung für den Konstruktor von container<int> auf diese Weise schreiben kann

Ich möchte in der Lage sein, einen ähnlichen Konstruktor für container<thing<T>> zu definieren. Ich denke, was ich bin versucht, eine partielle Spezialisierung einer Template-Funktion zu schreiben, ist hier, was ich bin versucht (was illegal ist.):

template <class T> 
container<thing<T>>::container() { 

} 

Diese nicht kompiliert.

Ich bin nicht ganz sicher, was der richtige Weg zur Lösung dieses Problems ist und die Grenzen zwischen dem, was eine Überladung und eine Spezialisierung für eine Vorlage-Klasse-Funktion sind verschwimmen. Kann das trivial gelöst werden oder wird type_traits (std::enable_if) benötigt? Wie kann ich das lösen?

Antwort

7

Sie können nicht teilweise den Konstruktor spezialisieren, aber Sie müssen nicht unbedingt zu einer teilweisen die vollständige Klasse spezialisieren.

Kann dies trivial gelöst werden oder erfordert es type_traits/enable_if? Wie kann ich das lösen?

Delegieren Konstruktoren und Tag-Dispatching kann die Begrenzung umgehen.
Es folgt ein minimales, Arbeitsbeispiel:

#include<iostream> 

template <class... T> 
class thing {}; 

template <class T> 
class container { 
    template<typename> 
    struct tag {}; 

    template<typename U> 
    container(int, tag<thing<U>>) { 
     std::cout << "thing<U>" << std::endl; 
    } 

    container(char, tag<T>) { 
     std::cout << "normal constructor" << std::endl; 
    } 

public: 
    container(): container(0, tag<T>{}) {} 
}; 

int main() { 
    container<int> c1; 
    container<thing<int>> c2{}; 
} 

es Siehe auf wandbox.


Beachten Sie, dass es leicht erweitern können, wenn Sie mehr als zwei delegierenden Konstrukteure haben wollen, aus denen den richtigen zu holen.
Als Beispiel:

#include<iostream> 

template <class... T> 
class thing {}; 

template<typename> struct tag {}; 
template<int N> struct prio: prio<N-1> {}; 
template<> struct prio<0> {}; 

template <class T> 
class container {  
    template<typename U> 
    container(prio<2>, tag<thing<U>>) { 
     std::cout << "thing<U>" << std::endl; 
    } 

    container(prio<1>, tag<double>) { 
     std::cout << "double" << std::endl; 
    } 

    container(prio<0>, tag<T>) { 
     std::cout << "normal constructor" << std::endl; 
    } 

public: 
    container(): container(prio<2>{}, tag<T>{}) {} 
}; 

int main() { 
    container<int> c1; 
    container<double> c2; 
    container<thing<int>> c3{}; 
} 

Sehen Sie es auf wandbox.

+1

sehr elegante Lösung (IMHO) – max66

+0

@ max66 zu definieren. Die teilweise Spezialisierung der gesamten Klasse kann schnell zu Code-Duplikation führen. Normalerweise versuche ich, sie möglichst zu vermeiden. – skypjack

+0

@ max66 Nur bei mehreren _specialized_ Konstruktoren mehr Details hinzugefügt. Ich hoffe es gefällt dir auch. ;-) – skypjack

4

Sie können nicht teilweise spezialisieren den Konstruktor, aber Sie können teilweise spezialisieren sich die vollständige Klasse

template <class T> 
class container<thing<T>> 
{ 
    public: 
     container() { } 
}; 
+0

auf diese Weise muss ich die Klasse vollständig (neu) definieren, richtig? – user2079802

+0

@ user2079802 - ja; Wenn jedoch der Teil der Klasse, den Sie (neu) definieren müssen, im Vergleich zur vollständigen Klasse klein ist, können Sie eine kleine Basisklasse mit nur dem zu definierenden/neu zu definierenden Teil erstellen. – max66

+0

@ user2079802 - siehe auch die Lösung von skypjack: den Konstruktor nicht partiell spezialisieren, aber das Kombinieren von Tag-Dispatching und Delegieren von Konstruktoren kann das Problem lösen, ohne die Klasse – max66

Verwandte Themen