Historie der Frage:
Templates wurden in C++ eingeführt, um die effiziente Implementierung universeller Algorithmen und Datenstrukturen zu ermöglichen. Von Anfang an war ein Mechanismus zur automatischen Typableitung aus den Eingabeargumenten erforderlich, um die Verwendung von Templates für Entwickler bequemer zu machen.
Problem:
Der Substitutionsmechanismus ist nicht immer offensichtlich: Es entstehen Mehrdeutigkeiten mit Referenzen, Typmaskierungen, partiellen Spezialisierungen, Referenz-Template-Parametern und Konstanten. Manchmal kann der Compiler den Typ nicht ableiten oder gibt ein unerwartetes Ergebnis aus.
Lösung:
Der Compiler analysiert die Argumente, vergleicht sie mit den Template-Parametern unter Berücksichtigung der Regeln für cv-Qualifizierer, Referenzen und Zeiger. Mängel und Einschränkungen erfordern die explizite Angabe des Typs, wenn eine automatische Substitution nicht möglich ist.
Beispielcode:
template<typename T> void func(T arg) { /* ... */ } func(10); // T wird als int abgeleitet func("abc"); // T wird als const char* abgeleitet // Unterschied zwischen T arg und T& arg: template<typename T> void printRef(T& arg); // Nimmt kein temporäres Objekt an!
Wesentliche Merkmale:
Was passiert, wenn eine Template-Funktion T& annimmt und man versucht, ein temporäres Objekt zu übergeben?
Der Compiler kann den Typ nicht ableiten, da ein temporäres Objekt nicht über eine nicht-konstante Referenz übergeben werden kann. Es tritt ein Kompilierungsfehler auf.
template<typename T> void foo(T& arg); foo(42); // Fehler!
Wie funktioniert die Typableitung mit Arrays?
Arrays "verfallen" zu Zeigern bei der Übergabe per Wert, aber wenn das Template eine Referenz annimmt, bleibt die Größe des Arrays erhalten, was häufig zur Implementierung von safe-size Templates genutzt wird.
template<typename T, size_t N> void arraySize(T (&arr)[N]) { std::cout << N; } int x[10]; arraySize(x); // Gibt 10 aus
Warum ist es nicht immer korrekt, auto zur Speicherung von Ergebnissen von Template-Funktionsaufrufen zu verwenden?
Auto kann beim Ableiten des Typs const oder ref-Qualifizierer "abschneiden", was manchmal zu unerwarteten Kopier- oder Änderungsfehlern führt.
auto x = funcReturningRef(); // x wird per Wert und nicht als Referenz sein!
Die Template-Funktion für universelles Sortieren nimmt T&, der Benutzer versucht, ein temporäres Objekt zu übergeben. Infolgedessen kompiliert der Code nicht, und der Fehler führt zu Verwirrung beim Entwickler.
Vorteile:
Nachteile:
Der Sortierer wird über universelle Referenzen (T&&) mit std::forward implementiert, was es ermöglicht, sowohl mit lvalue als auch mit rvalue gut zu arbeiten, wodurch die Leistung und Flexibilität erhöht werden.
Vorteile:
Nachteile: