Typumwandlung bei Template-Argumente
-
Hallo,
da gibts etwas was ich noch nie so richtig gerrafft habe.
[Effektiv C++, 3. Auflage, Tipp: 47]Es geht um folgendes.
template<class T> class Rational { public: Rational(const T& numerator = 0,const T& denominator = 1); }; template<class T> const Rational<T> operator*(const const Rational<T>& lhs,const Rational<T>& rhs) { ... }Nun führ dieser Auruf zu einem Fehler:
Rational<int> sinn(1,2); Rational<int> res = sinn * 2; // FehlerBei einer NichtTemplate Klasse wäre das OK, weil die 2 implizit durch den nicht expliciten C'tor in ein Rational Objekt umgewandelt werden könnte.
Doch bei Templates funktioniert das nicht, denn Zitat: "Impliziete Typumwandlungsfunktion werden nie zur Herleitung von Template-Argumenten herangezogen".
Wieso ist das so, wieso erzeugt der Compiler wenn er die 2 sieht nicht einen Rational<int>, er muss sie ja sogar nicht erzeugen, weil er ja durch sinn schon eins hat.
Die Erklärung habe ich nicht ganz verstanden.
Frage : Kann mir das einer erklären
???Der Rest ist mir dann klar, wie das dann mit friend abläuft. Nur das obere nicht, womit ich die Lücke zw. Problem und Lösung nicht schließen kann.
-
Doch bei Templates funktioniert das nicht, denn Zitat: "Impliziete Typumwandlungsfunktion werden nie zur Herleitung von Template-Argumenten herangezogen".
Das Ganze hat nicht speziell etwas mit Typumwandlungsfunktionen zu tun. Vielmehr liegt das an den allgemeinen Deduktionsregeln.
Bei der Herleitung von Template-Parametern wird für jedes Argument-Parameter-Paar eine passende *Substitution* gesucht. Also: "mit welchem Typ muss ich den Template-Parameter ersetzen, damit er auf das Argument passt".
Dabei wird immer ein "exact match" gesucht bzw. sind nur wenige Konvertierungen erlaubt.Grundsätzlich muss man zwischen Referenz- und "normalen"-Parametern unterscheiden: falls der Parameter eine Referenz ist, dann wird nur der Typ des Arguments berücksichtig. Die einzig erlaubten Konvertierungen sind zuätzliche const/volatile Qualifaktionen sowie derived-to-base-Konvertierungen.
Bsp:template <class T> void f(const T& a, const T& b); int main() { f("Hallo", "Welt"); // error }Der Typ von a ist const char[6]. Der von b const char[5]. T kann aber nicht beides sein -> Error.
Andernfalls findet ein "decaying" von Array und Funktionen zu Pointern statt. Außerdem werden top-level const/volatile-Qualifikationen ignoriert.
Andere Konvertierungen, wie z.B. benutzer-definierte, sind grundsätzlich nicht erlaubt.template <class T> void f(T a, T b); int main() { f("Hallo", "Welt"); // OK. T = char* }Am Ende müssen alle Substitutionen eindeutig sein, andernfalls schlägt die Herleitung fehl.
In deinem Beispiel würde T für den ersten Parameter als int hergeleitet. Für den zweiten gibt es keine Herleitung. Damit ist ingesamt keine Herleitung möglich.
Würde man benutzer-definierte Konvertierungen zulassen, dann hättest du in deinem Fall eine eigenartige Situation: du hast einen Template-Parameter, der einmal mit int und einmal mit "Konvertierung von int nach Rational<int>" substituiert wird - ein schizophrenes T.
-
OK
Vielen Dank für die Erklärung ...