============ Überladungen [TOC] ============ C++ unterstützt das Überladen (_overloading_) von Namen. Das betrifft insbesondere Deklarationen von Funktionen, Methoden und Templates. Überladungen sind nur zulässig, wenn eine Unterscheidung aufgrund der Parameter bzw. Template-Parameter möglich ist. Folgende Überladung ist beispielsweise unzulässig, weil sich die beiden Funktionsdeklarationen nur beim Return-Typ unterscheiden und somit eine Differenzierung aufgrund der Parameter nicht möglich ist: :import: session05/examples/bad-overloading.cpp ---- SHELL (path=session05/examples,hostname=theon) -------- g++ -Wall -c bad-overloading.cpp ---------------------------------------------------------- Solange die Unterscheidbarkeit gegeben ist, dürfen beliebig viele Deklarationen den gleichen Namen verwenden. Wenn dann der Name genutzt wird, findet eine Auswahl in zwei Phasen statt: * Feststellung aller zulässigen Kandidaten. Kandidaten werden entfernt u.a. aufgrund - einer nicht passenden Parameterzahl (wobei hier Dinge wie Default-Werte und variabel lange Parameterlisten zu berücksichtigen sind), - einer fehlenden Konvertierbarkeit von den aktuellen zu den formalen Parametern und aufgrund - von SFINAE bei Templates. * Sortierung der verbliebenen Kandidaten nach einer Liste von Kriterien. Hierzu gehören in dieser Reihenfolge u.a. folgende Kriterien: - Konsequent größere Nähe bei der Konvertierbarkeit - Bessere Passung bezüglich der Referenzen - Nicht-Template-Funktionen oder -Methoden haben Vorrang vor Template-Funktionen und -Methoden. - Bessere Passung bei den Template-Parametern. Wenn bei der ersten Phase kein Kandidat übrigbleibt, ist es ein Fehler. Neuere Übersetzer liefern dann typischerweise eine Liste der namentlich passenden Deklarationen, wobei sie dann jeweils begründen, warum sie nicht passen. Das führt oft zu längeren Fehlermeldungen: :import: session05/examples/no-candidates.cpp ---- SHELL (path=session05/examples,hostname=theon) -------- g++ -Wall -c no-candidates.cpp ---------------------------------------------------------- Die bei der zweiten Phase zur Anwendung kommende Ordnung ist nur partiell, d.h. diese Phase kann damit enden, dass wir am Ende mehrere gleichrangig gute Kandidaten haben. Das wird als Fehler behandelt: :import: session05/examples/ambiguous.cpp ---- SHELL (path=session05/examples,hostname=theon) -------- g++ -Wall -c ambiguous.cpp ---------------------------------------------------------- Die hier verwendete Zeichenkette `"hi"` ist vom Datentyp `const char [3]` (zwei Zeichen plus Nullbyte), die wegen der Dualität von Zeigern und Arrays aber auch ohne Konvertierung als `const char*` interpretiert werden kann. Aufgabe ======= Schreiben Sie eine Funktion _dim_, die die Dimensionierung verschiedener Argumente liefert. Zu unterstützen sind * zur Übersetzzeit festdimensionierte Arrays, * Objekte, die eine Methode size() haben und * `char**`, wobei hier (wie bei _argv_) davon ausgegangen werden soll, dass ein Nullzeiger als Terminierung dient. Folgendes Testprogramm sollte damit funktionieren: :import: session05/step01/testit.cpp ---- SHELL (path=session05/step01,hostname=theon) -------- g++ -Wall -o testit testit.cpp ./testit 1 2 3 4 5 6 ---------------------------------------------------------- Zu beachten sind folgende Punkte: * Alle Varianten sollten funktionieren, auch wenn die Parameter nur lesenderweise zur Verfügung stehen. Trickreich ist das bei `char**`, denn mit `const char**` klappt es nicht. Warum? * Sofern ein Ergebnis zur Übersetzzeit ermittelbar ist, sollten Sie beim Return-Typ `constexpr` angeben. Würde es bei folgendem Beispiel Übersetzungsfehler geben? :import: session05/step01/test-declarations.cpp Überlegen Sie sich das kurz, ohne das mit dem g++ zu übersetzen. Wo kann hier `constexpr` zum Zuge kommen? * Setzen Sie SFINAE ein, wenn sonst eine Template-Funktion zu allgemein wäre. Hinweis: In diesem Fall ist dies noch recht einfach, die Nutzung von `decltype` genügt. Bedenken Sie, dass der Return-Typ auch nach der Parameterliste stehen kann: ---- CODE (type=cpp) ------------------------------------------------------- template auto dim(/* ... */) -> decltype(/* ... */) { /* ... */ } ---------------------------------------------------------------------------- Mit diesem Konstrukt können wir auf einem Schlag - den Return-Typ richtig bestimmen und - dafür sorgen, dass dieser Kandidat per SFINAE ausscheidet, wenn der in `decltype` angegebene Ausdruck für _T_ inkorrekt ist. :navigate: up -> doc:index next -> doc:session05/page02