Member templates
Template-Deklarationen ( class , function , und variables (seit C++14) ) können innerhalb einer Member-Spezifikation jeder Klasse, Struktur oder Union erscheinen, die keine lokalen Klassen sind.
#include <algorithm> #include <iostream> #include <string> #include <vector> struct Printer { // generischer Funktor std::ostream& os; Printer(std::ostream& os) : os(os) {} template<typename T> void operator()(const T& obj) { os << obj << ' '; } // Member-Template }; int main() { std::vector<int> v{1,2,3}; std::for_each(v.begin(), v.end(), Printer(std::cout)); std::string s{"abc"}; std::ranges::for_each(s, Printer(std::cout)); }
Ausgabe:
1 2 3 a b c
Partielle Spezialisierungen von Member-Templates können sowohl im Klassenbereich als auch im umschließenden Namensraumbereich erscheinen. Explizite Spezialisierungen können in jedem Bereich erscheinen, in dem das primäre Template erscheinen kann.
struct A { template<class T> struct B; // primäres Mitgliedstemplate template<class T> struct B<T*> {}; // OK: partielle Spezialisierung // template<> struct B<int*> {}; // OK via CWG 727: vollständige Spezialisierung }; template<> struct A::B<int*> {}; // OK template<class T> struct A::B<T&> {}; // OK
Wenn die Deklaration der einschließenden Klasse selbst eine Klassentemplate ist, nimmt eine Membertemplate, die außerhalb des Klassenkörpers definiert wird, zwei Sätze von Template-Parametern: einen für die einschließende Klasse und einen weiteren für sich selbst:
template<typename T1> struct string { // Mitgliedsvorlagenfunktion template<typename T2> int compare(const T2&); // Konstruktoren können ebenfalls Vorlagen sein template<typename T2> string(const std::basic_string<T2>& s) { /*...*/ } }; // Außerhalb der Klassendefinition von string<T1>::compare<T2> template<typename T1> // für die umschließende Klassenvorlage template<typename T2> // für die Mitgliedsvorlage int string<T1>::compare(const T2& s) { /* ... */ }
Inhaltsverzeichnis |
Memberfunktionsvorlagen
Destruktoren und Copy-Konstruktoren können keine Templates sein. Falls ein Template-Konstruktor deklariert wird, der mit der Typsignatur eines Copy-Konstruktors instanziiert werden könnte, wird stattdessen der implizit deklarierte Copy-Konstruktor verwendet.
Eine Member-Funktionsvorlage kann nicht virtuell sein, und eine Member-Funktionsvorlage in einer abgeleiteten Klasse kann keine virtuelle Member-Funktion aus der Basisklasse überschreiben.
class Base { virtual void f(int); }; struct Derived : Base { // diese Member-Template überschreibt Base::f nicht template<class T> void f(T); // nicht-template Member-Überschreibung kann das Template aufrufen: void f(int i) override { f<>(i); } };
Eine Nicht-Template-Memberfunktion und eine Template-Memberfunktion mit demselben Namen können deklariert werden. Im Konfliktfall (wenn eine Template-Spezialisierung exakt mit der Signatur der Nicht-Template-Funktion übereinstimmt), bezieht sich die Verwendung dieses Namens und Typs auf die Nicht-Template-Member, es sei denn, eine explizite Template-Argumentliste wird angegeben.
template<typename T> struct A { void f(int); // Nicht-Template-Member template<typename T2> void f(T2); // Member-Template }; // Template-Member-Definition template<typename T> template<typename T2> void A<T>::f(T2) { // Code-Auschnitt } int main() { A<char> ac; ac.f('c'); // ruft Template-Funktion A<char>::f<char>(char) auf ac.f(1); // ruft Nicht-Template-Funktion A<char>::f(int) auf ac.f<>(1); // ruft Template-Funktion A<char>::f<int>(int) auf }
Eine außerhalb der Klasse definierte Definition einer Member-Funktionsvorlage muss
äquivalent
zur Deklaration innerhalb der Klasse sein (siehe
function template overloading
für die Definition von Äquivalenz), andernfalls wird sie als Überladung betrachtet.
struct X { template<class T> T good(T n); template<class T> T bad(T n); }; template<class T> struct identity { using type = T; }; // OK: äquivalente Deklaration template<class V> V X::good(V n) { return n; } // Fehler: nicht äquivalent zu einer der Deklarationen innerhalb von X template<class T> T X::bad(typename identity<T>::type n) { return n; }
Konvertierungsfunktionsvorlagen
Eine benutzerdefinierte Konvertierungsfunktion kann eine Template sein.
struct A { template<typename T> operator T*(); // Konvertierung zu Zeiger auf beliebigen Typ }; // Definition außerhalb der Klasse template<typename T> A::operator T*() { return nullptr; } // Explizite Spezialisierung für char* template<> A::operator char*() { return nullptr; } // Explizite Instanziierung template A::operator void*(); int main() { A a; int* ip = a.operator int*(); // Expliziter Aufruf von A::operator int*() }
Während der Überlagerungsauflösung werden Spezialisierungen von Konvertierungsfunktionsvorlagen nicht durch Namenssuche gefunden. Stattdessen werden alle sichtbaren Konvertierungsfunktionsvorlagen berücksichtigt, und jede durch Template-Argumentableitung erzeugte Spezialisierung (die spezielle Regeln für Konvertierungsfunktionsvorlagen hat) wird verwendet, als wäre sie durch Namenssuche gefunden worden.
Using-Deklarationen in abgeleiteten Klassen können nicht auf Spezialisierungen von Template-Konvertierungsfunktionen aus Basisklassen verweisen.
|
Eine benutzerdefinierte Konvertierungsfunktionsvorlage kann keinen abgeleiteten Rückgabetyp haben: struct S { operator auto() const { return 10; } // OK template<class T> operator auto() const { return 42; } // error }; |
(seit C++14) |
Member-Variablen-TemplatesEine Variablen-Template-Deklaration kann im Klassenbereich erscheinen, in diesem Fall deklariert sie ein statisches Datenelement-Template. Siehe Variablen-Templates für Details. |
(seit C++14) |
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 1878 | C++14 | operator auto war technisch erlaubt | operator auto verboten |