Template funktion nicht erkannt



  • Sorry für den Titel, aber das ist ohne Bsp schwer erklärbar:
    Ich habe hier einen, für std::ostream überladenen operator<<:

    template <typename T>
    std::ostream & 
    operator<< (std::ostream &stream, typename Mesh<T>::Triangle &tri)
    {
    	stream << "{" << tri.a.x << ";" << tri.a.y << ";" << tri.a.z << "}" << std::endl;
    	stream << "{" << tri.b.x << ";" << tri.b.y << ";" << tri.b.z << "}" << std::endl;
    	stream << "{" << tri.c.x << ";" << tri.c.y << ";" << tri.c.z << "}" << std::endl;
    	return stream;
    };
    

    und

    template <typename T>
    class Mesh
    {
    public:
    	struct Triangle
    	{
    		struct Point
    		{
    			T x, y, z;
    		} a, b, c;
    	};
    //.....
    };
    

    Der gcc schluckt das auch anstandslos, nur wenn ich den operator zb so aufrufe

    std::cout << tri;
    

    wobei tri ein Mesh<float>::Triangle ist, findet er keinen passenden operator.

    [edit]
    Was ich vergessen habe:
    Wenn ich die Funktion auf float spezialisiere:

    std::ostream & 
    operator<< (std::ostream &stream, Mesh<float>::Triangle &tri)
    {
    	stream << "{" << tri.a.x << ";" << tri.a.y << ";" << tri.a.z << "}" << std::endl;
    	stream << "{" << tri.b.x << ";" << tri.b.y << ";" << tri.b.z << "}" << std::endl;
    	stream << "{" << tri.c.x << ";" << tri.c.y << ";" << tri.c.z << "}" << std::endl;
    	return stream;
    };
    

    funktioniert alles problemlos
    [/edit]



  • Hallo,

    operator<< (std::ostream &stream, typename Mesh<T>::Triangle &tri)

    Das Mesh<T>::Triangle ist ein sogenannter "non-deduced-context". Ein solcher kann und wird niemals für die Herleitung eines Template-Parameters verwendet.



  • [OT]
    Nur so aus Interesse: Baust du ein Programm zur 2D-Gittererzeugung/Delaunay-Triangulierung?
    [/OT]



  • @Hume: Danke!

    @fubar:
    Die Klasse ist für ein 3D Gitter und das ganze wird irgendein 3D Spiel (wenn ich nur wüsste was für eins, viell ein 3D Pong). Aber ich bin noch beim Bau vom Grundgerüst, sprich Kapselung der Graphik API, und bau des Klassenmodells. Dieses Template hab ich eigentlich nur gemacht, um noch nicht entscheiden zu müssen ob ich doubles oder floats für die Vertices verwende ;).

    Nur so aus Interesse: gäbe es eine Möglichkeit, trotz diesem non-deduced-context problem die Typenspezialisierung in std::ostream zu verschieben und nicht selber spezialisiern zu müssen?


  • Mod

    wenn du nie mehrere instanzen des templates brauchst, könntest du die wahl zw. float und double ja auch durch ein simples typedef lösen.

    ansonsten geht es evtl. wenn du Mesh in einen eigenen namespace verbannst und den operator << als

    template <typename T>
    std::ostream &
    operator<< (std::ostream &stream, T &tri)
    // etc.
    

    schreibst. innerhalb des operators musst du dann nat. explizit auf die std:: version von << bezug nehmen. ist aber nur ein gedanke.



  • Das Problem mit typedefs ist, das für auch die Funktionen zum Zeichnen anders sind (glVertex3f vs glVertex3d) bei Templates löst man das elegent mit Spezialisierung, wohingegen man bei Typedefs auf Makros umsteigen muss, oder vielleicht auch überladene, geinlinete defVertex Funktionen.

    ansonsten geht es evtl. wenn du Mesh in einen eigenen namespace verbannst ...

    Das ist er, hat mit dem Problem nichts zu tun wenn ich das richtig verstanden habe

    Das Problem mit

    template <typename T>
    std::ostream &
    operator<< (std::ostream &stream, typename Mesh<T>::Triangle &tri) // nicht T &tri
    // etc.
    

    Ist, das es möglicherweise zwei spezialisierungen von Mesh gibt, in denen Triangle gleich definiert ist (hehe, google weis alles 😉 ).

    Allerding (Frage an einen experten): Wieso bezieht der Compiler bei der Auflösung des Typs von tri nicht nicht die beinhaltende Klasse mit ein? Also wenn ich das richtig verstanden habe, sieht der Compiler nur

    [cpp]
    typeof tri =
    struct{
    struct{
    float, float, float //aha gesuchter Typ T
    } // *3
    }
    [/cpp]

    Und kann daher nicht genau feststellen aus welcher Spezialisierung des Templates dieser Typ stammt.
    Aber wieso bezieht er nich mit ein, das der Typ aus der Spezialisierung für T (falls vorhanden, ansonsten die generische version) ist? Was übersehe ich? Hilfe!! 😕
    Bitte um Aufklärung.

    /// edit

    Was ich damit meine, ist: An der Aufrufenden Seite ( cout << tri; ) ist bekannt aus welcher Instanz des Templates tri stamm ( Mesh<float>::Triangle ). Wieso, geht diese Information beim Aufrufen verloren / wird nicht beachtet, sodas keine eindeutige Typauflösung stattfinden kann?

    Das Problem ist klar zB bei folgendem Problem:

    template <typename T>
    class A{
        typedef T ClassSuperSpezialType;
    };
    
    // und dann 
    
    template <typename T>
    void foo (A<T>::ClassSuperSpezialType){};
    
    //und dann
    
    foo (float); // Es kann sein, das ClassSuperSpezialType in einer Spezialisierung anders definiert ist
    
    // aber bei :
    A<float>::SuperSpezialType bar;
    foo(bar);
    // Müsste doch bekannt sein, das bar aus A<float> stammt ...
    

    Ich hoffe mein Verständnisproblem ist hiermit klarer geworden



  • Achso, ich meinte auch eigentlich 3D-Gittererzeugung. Frage nur, weil der Code fast so aussah wie das, was ich zur Zeit schreibe. Dann hätte ich nämlich bei dir abgucken können 😉

    Muss Triangle denn unbedingt innnerhalb von Mesh deklariert werden?



  • fubar schrieb:

    Muss Triangle denn unbedingt innnerhalb von Mesh deklariert werden?

    Habe ich gemacht, damit man zB schreiben kann:

    Mesh<float> bar;
    

    Und damit automatisch die Vertices in float Genauigkeit sind.



  • Nur mal eine Frage:
    Ich habe den Operator wie gesagt (notgedrungen) ausserhalb der Klasse, aber im selben Namespace deklariert.

    Allerdings habe ich ich vor dem Aufruf kein "using Namespace GLFW;", ich spreche alle meine Funktionen/Klassen mit GLFW::foo() an.
    Allerdings funtioniert das natürlich bei dem operator<< nicht, cout << tri; .
    Oh gott, bin ich dämlich. Und das fällt mir jetzt ein, wo ich schon die Hälfte umgebaut habe. Bitte sagt mir, das ein, im globalen Namespace positioniertes

    template <typename T>
    std::ostream & 
    operator<<(std::ostream& stream, GLFW::Mesh<T>::Triangle &tri) {};
    

    Auch nicht funktioniert hätte.



  • template <typename T> 
    class Mesh 
    { 
        public:
            ...
        private: 
            std::list<Triangle<T> > triangles_;
    };
    
    template <typename T>
    struct Triangle 
    {
        Point<T> p1, p2, p3;
    }
    

    Oder habe ich das falsch verstanden?

    Mesh<float> bar;
    

    würde doch so auch gehen 😕



  • Würde auch gehn. Ist blos geschmackssache.
    Ich dachte es wäre so eleganter, da Dreiecke immer Teil eines Meshes sind. Aber das war wohl eh blödsinn, denn für Gelände werde ich was anderes Definieren, falls das wirklich was grosses wird.

    [OT] was genau machst du eigentlich grade? [/OT]



  • Ich schreibe gerade ein Programm (was bestimmt nie ganz fertig wird ...) zur unstrukturierten Gittererzeugung (ein Gebiet wird in Dreiecke/Tetraeder zerlegt und diese Dreiecke/Tetraeder sollen bestimmte Qualitätsbedingungen erfüllen) und da habe ich auch so Sachen wie Mesh, Triangle, Line, Point usw.



  • ...ich weiß, daß es eine sehr späte Antwort ist, aber ich hatte gerade das gleiche Problem bei meiner template<class T>class Matrix und habe eine Lösung gefunden, wie man den op<< für <T> überladen kann (thx' to deadlef 🙂 )
    und zwar, wenn du die freien template Funktionen, sofort in dem namespace definierst und dort nicht nur den Prototyp angibst. kleines Beispiel am op<< für class Matrix (analog auch bei den anderen freien Funktionen):

    #ifndef _MATRIX_TEMPLATE_H_
    #define _MATRIX_TEMPLATE_H_
    
    #include<iostream>
    
    namespace dim2{
    
    	template< class T >
    	class Matrix{
    
    		private:  //.......Eigenschften/Attribute									
            public:  //........Elementfunktionen usw
    
    	};//end-of-class-Matrix
    			//	freie Funktionen 									
                template< class T >
    			std::ostream & operator<<(std::ostream & os, const dim2::Matrix<T> & mat){
    				os << "Matrix (" << mat.get_nRows() 
    				   << " X "      << mat.get_nCols() 
    				   << "):" << std::endl;
    
    				for(int row=0; row<mat.get_nRows() ;row++){
    					for(int col=0; col<mat.get_nCols() ;col++){
    
    						os << mat.get_elem(row,col) << " ";
    					}
    					os << std::endl;
    				}
    				return os;
    			}//end-of-operator<<
    
    //Implementation der Methoden/Elemntfkt der generischen Klasse Matrix				
    //......
    
    }//end-of-namespace-dim2
    #endif  //_MATRIX_TEMPLATE_H_
    

    post scriptum: wenn es dann noch immer nicht funktioniert: unter settings(alt+F7), bei Link subsystem:console einstellen 😉


Anmelden zum Antworten