Overload resolution in Template Funktion



  • Hallo

    #include <iostream>
    using namespace std;
    
    template<typename T>
    void bar(T)
    {
    	std::cout << "test(T)" << std::endl;
    }
    
    template<typename A>
    void foo(A)
    {
    	bar(A());
    }
    
    void bar(int)
    {
    	std::cout << "test(int)" << std::endl;
    }
    
    int main()
    {
    	foo(0);
    	bar(0);
    }
    

    Kompiliert mit GCC 4.x wird mir

    test(T)
    test(int)
    

    ausgegeben.
    Wieso ist das so? bar ist ein abhängiger Name, daher sollte der Lookup in foo erst zu Instantiierungs-Zeit erfolgen. Zu dieser Zeit ist aber bar(int) die Beste Möglichkeit?!

    Danke



  • Probiere mal folgenden Code, er könnte die Antwort liefern, welcher Typ erkannt wird:

    #include <iostream>
    #include <typeinfo>
    using namespace std; 
    
    template<typename T> 
    void bar(T) 
    { 
      std::cout << "test(" << typeid(T).name() << ")" << std::endl; 
    } 
    
    int main(int argc, char* argv[]) 
    {
      bar(0); 
      return 0;
    }
    

    Unter meinem MSVC ist "0" ohne anderes Zutun ein int und die Ausgabe entspricht deiner Erwartung (also 2 mal "test(int)"). Das erinnert mich an die NULL - nullptr Debatte. Ich bin gespannt welcher Typ für bar(0) bei deinem Compiler rauskommt 🕶 ...

    lg XOR 🙂



  • xor schrieb:

    Probiere mal folgenden Code, er könnte die Antwort liefern, welcher Typ erkannt wird:

    #include <iostream>
    #include <typeinfo>
    using namespace std; 
    
    template<typename T> 
    void bar(T) 
    { 
      std::cout << "test(" << typeid(T).name() << ")" << std::endl; 
    } 
    
    int main(int argc, char* argv[]) 
    {
      bar(0); 
      return 0;
    }
    

    Unter meinem MSVC ist "0" ohne anderes Zutun ein int und die Ausgabe entspricht deiner Erwartung (also 2 mal "test(int)"). Das erinnert mich an die NULL - nullptr Debatte. Ich bin gespannt welcher Typ für bar(0) bei deinem Compiler rauskommt 🕶 ...

    lg XOR 🙂

    Ich habe leider kein GCC gerade hier, daher kann ich nicht testen. Der Typ ist aber definitiv int, denn ein

    template<>
    void bar(int)
    {
        std::cout << "test(int)" << std::endl;
    }
    

    funktioniert wunderbar, es wird zwei mal test(int) ausgegeben. Mm. nach muss es aber eben auch ohne Spezialisierung funktionieren, ein einfaches Überladen sollte auch gehen!



  • DummWieBrot schrieb:

    funktioniert wunderbar, es wird zwei mal test(int) ausgegeben. Mm. nach muss es aber eben auch ohne Spezialisierung funktionieren, ein einfaches Überladen sollte auch gehen!

    aus der main wird ja auch das "richtige" bar aufgerufen!


  • Mod

    DummWieBrot schrieb:

    bar ist ein abhängiger Name, daher sollte der Lookup in foo erst zu Instantiierungs-Zeit erfolgen. Zu dieser Zeit ist aber bar(int) die Beste Möglichkeit?!

    Beim unqualifizierten Lookup wird nur das Template gefunden, denn dieses Lookup erfolgt im Kontext der Templatedefinition.
    bar(int) könnte höchtens durch ADL gefunden werden,allerdings hat int keinen assozierten Namensraum.

    Das unqualifizierte Lookup muss bereits bei der Templatedefinition erfolgen, um den Ausdruck überhaupt interpretieren zu können.

    template<typename T>
    void foo();
    namespace x
    {
        namespace y
        {
            template<typename T>
            void bar()
            {
                foo(T()); // unqualifiziertes lookup findet ::foo und nicht x::foo
                          // nur deshalb ist das überhaupt erst ein Funktionsaufruf
            }
        }
        struct foo
        {
            foo(int);
        };
    }
    

  • Administrator

    @camper,
    Aber irgendwas scheint da trotzdem schief zu sein. Wenn du mal im Standard 14882:2003 schaust, Kapitel 14.6, Absatz 9, dann findest du dieses Beispiel:

    void f(char);
    
    template<class T>
    void g(T t)
    {
        f(1);    // f(char)
        f(T(1)); //dependent
        f(t);    //dependent
        dd++;    //not dependent
                 //error: declaration for dd not found
    }
    
    void f(int);
    double dd;
    
    void h()
    {
        g(2);   //will cause one call of f(char)followed
                // by two calls of f(int)
        g('a'); //will cause three calls of f(char)
    }
    

    Ich habe das mal ein wenig umgeschrieben und ausgeführt:

    #include <iostream>
    
    void f(char) { std::cout << "f(char)" << std::endl; }
    
    template<class T>
    void g(T t)
    {
        f(1);    // f(char)
        f(T(1)); //dependent
        f(t);    //dependent
        //dd++;  //not dependent
                 //error: declaration for dd not found
    }
    
    void f(int) { std::cout << "f(int)" << std::endl; };
    //double dd;
    
    int main()
    {
        g(2);   //will cause one call of f(char)followed
                // by two calls of f(int)
        g('a'); //will cause three calls of f(char)
    }
    

    Das Resultat war:

    f(char)
    f(char)
    f(char)
    f(char)
    f(char)
    f(char)
    

    Das stimmt doch nach Standard nicht?

    Version ist übrigens:
    g++ (TDM-2 mingw32) 4.4.1

    Grüssli



  • camper schrieb:

    DummWieBrot schrieb:

    bar ist ein abhängiger Name, daher sollte der Lookup in foo erst zu Instantiierungs-Zeit erfolgen. Zu dieser Zeit ist aber bar(int) die Beste Möglichkeit?!

    Beim unqualifizierten Lookup wird nur das Template gefunden, denn dieses Lookup erfolgt im Kontext der Templatedefinition.
    bar(int) könnte höchtens durch ADL gefunden werden,allerdings hat int keinen assozierten Namensraum.

    Das unqualifizierte Lookup muss bereits bei der Templatedefinition erfolgen, um den Ausdruck überhaupt interpretieren zu können.

    Nein. Dadurch, dass zum Zeitpunkt des Parsens von foo im gleichen Namespace kein Typ namens bar definiert ist, und foo selber nicht qualifiziert ist (::foo(T()) wär' was anderes!), ist klar, dass ein Funktionsaufruf gemeint ist. Welche Funktion wird definitiv durch ADL gemacht, und bei int wird zwangsläufig im global namespace geschaut!


  • Mod



  • Argh, ich habs verstanden. Danke camper, danke Dravere!


  • Administrator

    camper schrieb:

    Issues with two-stage lookup of dependent names

    Danke für den Link!
    camper irrt nie, sogar wenn es ein Beispiel im Standard gibt, dann liegt nicht camper falsch sondern der Standard ... 🤡 😃

    Grüssli


Anmelden zum Antworten