📐 1. Funktions-Templates (template<typename T>)
Templates ermöglichen es, Algorithmen unabhängig von konkreten Datentypen zu formulieren. Zur Compile-Zeit generiert der C++-Compiler (Monomorphisierung) für jeden verwendeten Typ eine optimierte Maschinenbauform:
#include <iostream>
#include <string>
// Generische Minimum-Funktion
template <typename T>
T min_value(T a, T b) {
return (a < b) ? a : b;
}
// Mehrere Template-Parameter
template <typename T, typename U>
auto add_heterogeneous(T a, U b) -> decltype(a + b) {
return a + b;
}
int main() {
std::cout << min_value(10, 20) << "\n"; // T = int
std::cout << min_value(3.14, 2.71) << "\n"; // T = double
std::cout << min_value<std::string>("Alpha", "Beta") << "\n"; // Explizit
}
Ein Template ist kein fertiges Bauteil, sondern eine Gussform (Blaupause). Wenn du min_value(5, 10) aufrufst, gießt der Compiler eine int-Version. Rufst du min_value(2.5, 4.1) auf, gießt er eine double-Version. Es gibt keinen Runtime-Overhead (Zero-Cost Abstraction)!
📦 2. Klassen-Templates & Non-Type Template Parameters (NTTP)
Klassen können generisch über Datentypen und über compile-zeitliche Konstanten (wie Array-Größen) parametrisiert werden:
#include <cstddef>
#include <stdexcept>
// T = Datentyp, Size = Compile-Zeit Konstante (NTTP)
template <typename T, std::size_t Size>
class StaticStack {
private:
T data_[Size];
std::size_t top_{0};
public:
void push(const T& item) {
if (top_ >= Size) throw std::overflow_error("Stack Overflow");
data_[top_++] = item;
}
T pop() {
if (top_ == 0) throw std::underflow_error("Stack Underflow");
return data_[--top_];
}
[[nodiscard]] std::size_t capacity() const { return Size; }
[[nodiscard]] std::size_t size() const { return top_; }
};
🔍 3. Explizite Template-Spezialisierung
Manchmal erfordern spezifische Datentypen (z.B. bool oder const char*) eine spezialisierte Behandlung:
// Primäres Template
template <typename T>
struct TypeFormatter {
static std::string format(const T& val) {
return "Generic: " + std::to_string(val);
}
};
// Vollständige Spezialisierung für std::string
template <>
struct TypeFormatter<std::string> {
static std::string format(const std::string& val) {
return "String: \"" + val + "\"";
}
};
// Spezialisierung für bool
template <>
struct TypeFormatter<bool> {
static std::string format(const bool& val) {
return val ? "Bool: TRUE" : "Bool: FALSE";
}
};
📑 4. Cheat-Sheet: C++ Template Konzepte
| Konstrukt | Syntax-Beispiel | Bedeutung & Verwendungszweck |
|---|---|---|
template<typename T> |
T square(T x) { return x * x; } |
Funktions-Template für beliebige numerische Typen |
| Class Template | template<typename T> class Buffer; |
Generischer Container oder Wrapper |
| NTTP (Non-Type) | template<typename T, size_t N> |
Größen oder Konstanten fest zur Compile-Zeit binden |
| Template Specialization | template<> struct Formatter<bool> |
Sonderlogik für bestimmte Typen definieren |
Type Alias (using) |
template<typename T> using Vec = std::vector<T>; |
Lesbare Alias-Namen für komplexe Template-Typen |
🧠 Diagnostischer Selbst-Check
Überprüfe dein Verständnis zu Speichersicherheit, Syntax und Systems-Design mit gezieltem Feedback:
🎯 Aufgaben & Checkliste in aufgabe.cpp
Weil der Compiler den Quellcode der Templates kennen muss, um konkrete Typ-Instanziierungen zu kompilieren, werden Template-Definitionen in C++ üblicherweise komplett in Header-Dateien (.hpp / .h) platziert!