Problem mit überladenen Template-Funktionen
-
Hallo,
hier mal ein kleines Problem, dass mich jetzt schon einige Nerven gekostet hat:#include <stdio.h> #include <time.h> #include <iostream> #include <utility> using namespace std; class Foo { public: template <typename T> Foo(T& t) { print(t); printc(t); } template <typename T> Foo(T* t) { print(t); printc(t); } template <typename T> void print(T& t) const { cout << "reference" << endl; } template <typename T> void print(T* t) const { cout << "pointer" << endl; } template <typename T> void printc(const T& t) const { cout << "const reference" << endl; } template <typename T> void printc(const T* t) const { cout << "const pointer" << endl; } }; int main () { int i = 0; Foo foo1(i); Foo foo2(&i); }Ausgabe:
reference
const reference
pointer
const referenceWarum zur Hölle wird statt der const Pointer nur die const Reference Überladung aufgerufen?
-
Sorry, habe einmal
printundprintcverwechselt.
-
Nö, ist mir nicht klar. Eigentlich ist doch der Compiler so schlau, Überladungen für Pointer-Typen zu erkennen. Sonst könnte man ja auch keine Template Container-Spezialisierungen für Pointer-Typen bauen.
Und bei der nicht-const Variante wird ja durchaus die richtige Überladung aufgerufen.
-
Hallo,
Ich denke, das deine Pointerversion von printc ein const T*, was ja ein Pointer auf ein konstantes Objekt ist, erwartet. Du übergibst aber einen konstanten Pointer auf nicht konstantes Objekt, das kann er nur als Referenz auflösen.
Füge doch einfach mal folgende Variante zu und schau was passiert.template <typename T> void printc( T* const t) const { cout << "pointer const" << endl; }
-
Braunstein schrieb:
Hallo,
Ich denke, das deine Pointerversion von printc ein const T*, was ja ein Pointer auf ein konstantes Objekt ist, erwartet. Du übergibst aber einen konstanten Pointer auf nicht konstantes Objekt, das kann er nur als Referenz auflösen.
Hmm, mit pointer to const funktionierts. Allerdings übergebe ich ja keinen Pointer auf eine konstantes Objekt, sondern nur einen nicht-const Pointer auf ein nicht-const Objekt.
Ich hätte an dieser Stelle erwartet, dass die implizite Konvertierung von nicht-const zu const-Pointern vorrang hat...
-
Braunstein schrieb:
Du übergibst aber einen konstanten Pointer auf nicht konstantes Objekt
Der Zeiger ist nicht konstant, bei
Foo()wirdTalsintdeduziert. Das gibt dann fürT*einenint*und keinenint* const...Braunstein schrieb:
das kann er nur als Referenz auflösen.
Nein, ohne
printc(const T& t)-Überladung ist wird ja auch die"const-pointer"-Version aufgerufen. Die Umwandlung vonT*nachT const*ist eine Standardkonvertierung.Die Umwandlung
T* -> T* const&besitzt eine höhere Priorität im Bezug auf Überladungsauflösung, weil hier nur ein Objekt an eineconst-Referenz gebunden wird. BeiT* -> T const*hingegen wird der Pointee-Typ selbst verändert (T -> T const), es liegt also eine höhere Indirektion vor. Der Überladungsauflösungsalgorithmus versucht ja grundsätzlich, Typen so wenig wie möglich anzupassen, und Top-Level-Referenz hinzufügen ist eben die kleinere Änderung.Ganz intuitiv ist die Sache aber schon nicht...
-
-
OK, danke, kann ich doch wieder ruhig schlafen
