DIGITAL
.h) ausformulieren. Dies liegt daran, dass Templates zur Compilezeit evaluiert werden, nicht erst beim Linken der Dateien, denn zum Zeitpunkt des Kompilierens kann ein Template noch nicht übersetzt werden, da zu diesem Zeitpunkt typischerweise noch nicht alle verwendeten Typen feststehen. Die einfache Lösung ist: Wir deklarieren und definieren Templates im Header und binden die Datei per #include ein wo auch immer wir es benötigen. Ein typischer Nachteil davon ist, dass in großen Projekten mit vielen Templates die Compilezeit zunmmt (alle Cpp-Dateien müssen bei einer Änderung eines eingebundenen Templates stets neu übersetzt werden) und die Dateigröße der resultierenden ausführbaren Datei nimmt zu, da jede Cpp, die das Template einbindet eine Kopie des Kompilierten Template-Codes enhält.
Auf Blatt 3 haben wir gesehen, wie man structs zur sinnvollen Gruppierung von Daten einsetzen kann. Braucht man viele solcher Gruppierungen, kann die Anzahl an structs schnell dazu führen, dass man die Übersicht verliert. Wir wollen jetzt mithilfe von Templates eine Alternative zu structs implementieren und deren Tradeoffs diskutieren. Als Basis verwenden wir folgende Deklaration:
template <typename First, typename Second>
struct pair {
First first;
Second second;
void swap(pair<First, Second> &other);
};
template <typename First, typename Second>
bool operator ==(const pair<First, Second> &lhs, const pair<First, Second> &rhs);
template <typename First, typename Second>
bool operator !=(const pair<First, Second> &lhs, const pair<First, Second> &rhs);
template <typename T>
void flip(pair<T, T> &p);
first und second initialisiert.== und !=.swap, die ein anderes pair mit denselben Typparametern akzeptiert und jeweils first und second zwischen den Paaren austauscht.pair eine freistehende Funktion flip, die innerhalb eines Paares die Werte von first und second vertauscht. T und nicht First und Second als Templateargument?pair ist dem Programmierer des Codes der Fehler unterlaufen, dass ein 2D-Punkt an eine Funktion übergeben wird, die eigentlich einen Bruch kürzen soll. Der Compiler kann diesen Fehler nicht erkennen, da für ihn beide Paare dieselbe Bedeutung haben. structs (eins für Punkte, eins für Brüche) so um, dass dieser Fehler zur Compilezeit gefunden wird. Überlegen Sie sich gleichzeitig sinnvolle Namen für die Membervariablen Ihrer structs (nicht first und second!)#include <numeric>
pair<int64_t, int64_t> project_point_onto_second_axis(const pair<int64_t, int64_t> &p) {
return pair<int64_t, int64_t>(p.first, 0);
}
pair<int64_t, int64_t> cancel_fraction(const pair<int64_t, int64_t> &p) {
// find greatest common divisor (c++17 and later)
int64_t gcd = std::gcd(p.first, p.second);
return pair<int64_t, int64_t>(p.first / gcd, p.second / gcd);
}
int main() {
// this is a fraction
pair<int64_t, int64_t> a(10, 4);
// this is a 2D point on an integer grid
pair<int64_t, int64_t> p(-2, 3);
pair<int64_t, int64_t> b = project_point_onto_second_axis(p);
pair<int64_t, int64_t> c = cancel_fraction(b);
std::cout << c.first << "\n";
}