Funktionstemplates
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 64 von 104.
Stellen Sie sich vor, Sie schreiben eine Funktion, um das Maximum von zwei Ganzzahlen zu finden, und stellen dann fest, dass Sie dieselbe Logik für Doubles und erneut für Strings benötigen. Ohne Templates müssten Sie fast identische Funktionen für jeden Typ schreiben. Funktionstemplates lösen dies, indem sie es Ihnen ermöglichen, die Logik einmal zu schreiben und den Compiler automatisch typspezifische Versionen generieren zu lassen.
Eine Funktionsvorlage verwendet das Schlüsselwort template, gefolgt von Template-Parametern in spitzen Klammern:
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}
int main() {
std::cout << maximum(5, 3) << std::endl; // Verwendet die int-Version
std::cout << maximum(3.14, 2.71) << std::endl; // Verwendet die double-Version
std::cout << maximum('a', 'z') << std::endl; // Verwendet die char-Version
}Der Compiler untersucht jeden Aufruf und generiert eine konkrete Funktion für diesen spezifischen Typ. Dieser Prozess wird als Template-Instanziierung bezeichnet. Sie können den Typ bei Bedarf auch explizit angeben:
std::cout << maximum<double>(5, 3.14) << std::endl; // Erzwingt die double-VersionTemplates können mehrere Typparameter haben, was noch flexiblere Designs ermöglicht:
template <typename T, typename U>
void printPair(T first, U second) {
std::cout << first << ", " << second << std::endl;
}
printPair(42, "hello"); // T=int, U=const char*
printPair(3.14, 100); // T=double, U=intFunktionstemplates bieten Polymorphismus zur Kompilierzeit – der Typ wird bestimmt, wenn der Code kompiliert wird, nicht zur Laufzeit. Dies bedeutet null Laufzeit-Overhead im Vergleich zu virtuellen Funktionen, was Templates ideal für performancekritischen generischen Code macht.
Aufgabe
EinfachLassen Sie uns ein Utility-Toolkit mit Funktions-Templates erstellen, um wiederverwendbare Operationen zu entwickeln, die mit jedem kompatiblen Typ funktionieren. Sie werden Ihre generischen Funktionen in einer Header-Datei organisieren und deren Flexibilität in Ihrem Hauptprogramm demonstrieren.
Sie werden zwei Dateien erstellen:
MathUtils.h: Definieren Sie eine Sammlung von Funktions-Templates, die gängige Operationen ausführen:minimum— eine Template-Funktion, die zwei Werte desselben Typs entgegennimmt und den kleineren zurückgibt.clamp— eine Template-Funktion, die drei Parameter entgegennimmt: einen Wert, eine Untergrenze (low bound) und eine Obergrenze (high bound). Sie gibt den innerhalb der Grenzen eingeschränkten Wert zurück (gibt low zurück, wenn der Wert kleiner als low ist, high, wenn der Wert größer als high ist, andernfalls den Wert selbst).swapValues— eine Template-Funktion, die zwei Referenzen desselben Typs entgegennimmt und deren Werte vertauscht.main.cpp: Lesen Sie sechs Eingaben ein (jede in einer separaten Zeile):- Erste Ganzzahl (Integer)
- Zweite Ganzzahl (Integer)
- Ein Double-Wert zum Eingrenzen (clamp)
- Untergrenze (double)
- Obergrenze (double)
- Ein Zeichen (Character)
Demonstrieren Sie Ihre Templates durch:
- Finden des Minimums der beiden Ganzzahlen und Ausgabe von:
Min of <a> and <b>: <result> - Finden des Minimums des Zeichens
'm'und Ihres eingegebenen Zeichens, Ausgabe von:Min of m and <char>: <result> - Eingrenzen (Clamping) des Double-Wertes und Ausgabe von:
Clamp <value> to [<low>, <high>]: <result> - Eingrenzen der ersten Ganzzahl auf den Bereich [0, 100] und Ausgabe von:
Clamp <value> to [0, 100]: <result> - Vertauschen der beiden Ganzzahlen und Ausgabe von:
After swapValues: <a>, <b>
Zum Beispiel mit den Eingaben 25, 10, 3.7, 1.0, 5.0 und z:
Min of 25 and 10: 10
Min of m and z: m
Clamp 3.7 to [1, 5]: 3.7
Clamp 25 to [0, 100]: 25
After swapValues: 10, 25Beachten Sie, wie jede Template-Funktion nahtlos mit Integern, Doubles und Zeichen funktioniert — der Compiler generiert die entsprechende Version für jeden Typ, den Sie verwenden. Ihre swapValues-Funktion sollte die ursprünglichen Variablen über Referenzen modifizieren, was zeigt, dass Templates mit Referenzparametern genauso funktionieren wie reguläre Funktionen.
Spickzettel
Funktionstemplates ermöglichen es Ihnen, generische Funktionen zu schreiben, die mit mehreren Typen funktionieren. Verwenden Sie das Schlüsselwort template gefolgt von Template-Parametern:
template <typename T>
T maximum(T a, T b) {
return (a > b) ? a : b;
}Der Compiler generiert automatisch typspezifische Versionen durch Template-Instanziierung:
maximum(5, 3); // Generates int version
maximum(3.14, 2.71); // Generates double version
maximum('a', 'z'); // Generates char versionSie können den Typ bei Bedarf explizit angeben:
maximum<double>(5, 3.14); // Forces double versionTemplates unterstützen mehrere Typparameter:
template <typename T, typename U>
void printPair(T first, U second) {
std::cout << first << ", " << second << std::endl;
}
printPair(42, "hello"); // T=int, U=const char*Templates funktionieren mit Referenzparametern zum Ändern von Originalwerten:
template <typename T>
void swapValues(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}Funktionstemplates bieten Compile-Zeit-Polymorphismus ohne Laufzeit-Overhead, was sie ideal für performancekritischen generischen Code macht.
Probier es selbst
#include <iostream>
#include "MathUtils.h"
using namespace std;
int main() {
// Eingaben lesen
int a, b;
double value, low, high;
char ch;
cin >> a;
cin >> b;
cin >> value;
cin >> low;
cin >> high;
cin >> ch;
// TODO: Verwende das minimum Template, um das Minimum von zwei Integern zu finden
// Ausgabe: "Min of <a> and <b>: <result>"
// TODO: Verwende das minimum Template, um das Minimum von 'm' und dem eingegebenen Zeichen zu finden
// Ausgabe: "Min of m and <char>: <result>"
// TODO: Verwende das clamp Template auf den double-Wert
// Ausgabe: "Clamp <value> to [<low>, <high>]: <result>"
// TODO: Verwende das clamp Template auf den ersten Integer mit dem Bereich [0, 100]
// Ausgabe: "Clamp <value> to [0, 100]: <result>"
// TODO: Verwende das swapValues Template auf die zwei Integer
// Ausgabe: "After swapValues: <a>, <b>"
return 0;
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container