Template-Friends in Verbindung mit Namensraum und abhängigem Typ



  • Guten Morgen.

    Für alle folgenden Codebeispiele sei diese Vorwärtsdeklaration gegeben:

    template <typename T>
    struct MyClass;
    

    Zuerst der Problemcode. Handelt es sich hier um fehlerhaftes C++? (Dass T beim Aufruf aus den Funktionsargumenten alleine nicht hergeleitet werden kann, ist mir bewusst – darum geht es hier nicht. Der gezeigte Code ist diesbezüglich korrekt).

    // (1)
    namespace ns
    {
    	template <typename T>
    	void Function(typename T::MemberType);
    }
    
    template <typename T>
    struct MyClass
    {
    	friend void ns::Function<T>(typename T::MemberType);
    };
    

    Ich erhalte beim Kompilieren folgende Fehler:

    error C2770: Ungültige explizite template-Argumente für "void ns::Function(T::MemberType)".
    error C2063: 'ns::Function': Keine Funktion

    Diese beiden Varianten (Änderungen als Kommentar) hingegen kompilieren ohne Probleme, auch wenn ich MyClass mit einem gültigen Typen instanziiere:

    // (2)
    // Kein Namensraum
    template <typename T>
    void Function(typename T::MemberType);
    
    template <typename T>
    struct MyClass
    {
    	// Kein ns::
    	friend void Function<T>(typename T::MemberType);
    };
    
    // (3)
    namespace ns
    {
    	// Kein Parameter mit abhängigem Typen MemberType
    	template <typename T>
    	void Function();
    }
    
    template <typename T>
    struct MyClass
    {
    	friend void ns::Function<T>();
    };
    

    Bei diesem Code hingegen erhalte ich allein durch die Deklarationen noch keine Fehler:

    // (4)
    namespace ns
    {
    	template <typename T>
    	void Function(typename T::MemberType);
    }
    
    template <typename T>
    struct MyClass
    {
    	// keine explizite Angabe des Parameters T, also nicht ns::Function<T>
    	friend void ns::Function(typename T::MemberType);
    };
    

    Erst bei der Template-Instanziierung von MyClass mit dem Code

    struct Test
    {
    	typedef int MemberType;
    };
    
    int main()
    {
    	MyClass<Test> a;
    }
    

    ergeben sich folgende Compilerfehler:

    error C2785: 'void ns::Function(T::MemberType)' und '<Unbekannt>' haben verschiedene Rückgabetypen
    error C2063: 'ns::Function': Keine Funktion

    Was schreibt der C++-Standard hier genau vor? Sofern ich nichts übersehen habe, gibt es laut 14.5.3 und 14.6.5 lediglich Probleme bei der Namensauflösung von nicht vollständig qualifizierten Funktionen, wenn sich diese in einem nicht unmittelbar umgebenden Namensraum befinden. Im Bezug auf friend -Funktionen im Kontext abhängiger Parametertypen habe ich nichts gefunden.

    Ich verwende Microsoft Visual Studio 2008, verhält sich dessen Compiler standardkonform?



  • Ich meine, dass es bei VS2008 ohne SP Probleme bei der Namensauflösung in Verbindung mit Templates gab. Ich finde leider auf die Schnelle keinen Link dazu. Falls Du es noch nicht hast, probiert mal SP1 zu installieren...[t]



  • Das Service Pack 1 hab ich wegen des TR1 bereits installiert.



  • Der MSVC2010 kann es auch nicht.
    Was aber geht:

    template <typename T>
    struct MyClass;	
    
    namespace ns
    {
        template <typename T>
        void Function(typename T::MemberType);
    }
    
    template <typename T>
    struct MyClass
    {
    	template<typename U>
    	friend void ns::Function<U>(typename U::MemberType);
    };	
    
    struct T
    {
    	typedef int MemberType;
    };
    
    int main()
    {
    	MyClass<T> x;
    }
    

    Sinds halt ein paar Friends mehr ;o)

    was dem ganzen vermutlich ein wenig näher kommt:

    template <typename T>
    struct MyClass;	
    
    namespace ns
    {
        template <typename T>
        void Function(typename T::MemberType)
    	{
    		;
    	}
    
    	template <typename T>
    	void FunctionHelper(T)
    	{
    		Function(typename T::MemberType());
    	}
    }
    
    template <typename T>
    struct MyClass
    {
        friend void ns::FunctionHelper<T>(T);
    };
    
    struct T
    {
    	typedef int MemberType;
    };
    
    int main()
    {
    	MyClass<T> x;
    }
    

    Was aber den Nachteil hat, dass die Parameter-Liste von Function unter Umständen ziemlich lang werden kann - je nach dem, was du dort machen willst... ^^

    Ansonsten scheint es so, als ob es zwar korrektes C++ wäre, aber der MSVC es einfach nicht kann.

    bb



  • Sollte eigentlich korrekt sein.

    Comeau, Codepad und gcc schlucken den Code auch (die erste Version). Aber VS kommt damit tatsächlich nicht klar. Egel welche Version...



  • Danke für die Antworten und besonders das Testen auf anderen Compilern! Es scheint sich also wirklich um einen Bug des Microsoft-Compilers zu handeln. Falls noch jemand eine Idee hat oder mehr über den C++-Standard in diesem Punkt weiss, wäre ich froh um weitere Meinungen!

    Als Workaround ist es wohl das Einfachste, eine Klasse als friend zu machen und static -Methoden anzubieten.


Anmelden zum Antworten