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 reference

    Warum zur Hölle wird statt der const Pointer nur die const Reference Überladung aufgerufen?



  • Sorry, habe einmal print und printc verwechselt.



  • 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() wird T als int deduziert. Das gibt dann für T* einen int* und keinen int* 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 von T* nach T 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 eine const -Referenz gebunden wird. Bei T* -> 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...


  • Mod



  • OK, danke, kann ich doch wieder ruhig schlafen 😃


Anmelden zum Antworten