Friend Methode für Template außerhalb definieren .



  • Klar ist dein operator<<() ein Template - schließlich bezieht er sich auf die Template-Klasse Array<>. Ansonsten hat BimBam seinen letzten Beitrag noch berichtigt.



  • Ok stimmt .
    Aber wodurch wird der Linker-Fehler verursacht ? 😕



  • Vermutlich durch die Regeln der Template-Instanziierung:

    friend ostream& operator << (ostream& ostr, const A<T>& a);
    

    erklärt dem Compiler, daß für jeden Array<T> ein passender operator<< existiert - die müsstest du alle einzeln schreiben.
    template<typename U>
    friend ostream& operator << (ostream& ostr, const A<U>& a);
    [/cpp]erklärt den Template-Operator als Freund deiner Klasse.



  • CStoll schrieb:

    Vermutlich durch die Regeln der Template-Instanziierung:

    friend ostream& operator << (ostream& ostr, const A<T>& a);
    

    erklärt dem Compiler, daß für jeden Array<T> ein passender operator<< existiert - die müsstest du alle einzeln schreiben.
    template<typename U>
    friend ostream& operator << (ostream& ostr, const A<U>& a);
    [/cpp]erklärt den Template-Operator als Freund deiner Klasse.

    Definiere ich den Operator innerhalb der Klassendefiniton bekomme ich diesen Fehler allerdings nicht . 😕

    #include <iostream>
    using std::ostream;
    using std::endl;
    
    template <class T>
    class Array
    {
        private:
    
            static int defaultsize;
            T *internArray;
            int size;
    
        public:
    
            int getDefaultSize()const; // 
            int getActualSize()const; // 
            void setDefaultSize(int Value); //
            T getElement(int place)const;
            void setElement(T obstacle,int place);
            Array();
            Array(int _size);
            ~Array();
            Array(const Array&);
            Array<T>& operator=(const Array<T>& rhs);
            Array<T> operator+(const Array<T>& rhs);
    
            //STREAM OPERATIONS
            friend ostream& operator <<(ostream& stream,const Array<T>& rhs)
           {
            for ( int i = 0 ; i < rhs.getActualSize() ; i ++) 
            { 
                stream << " Array an Stelle : " << i << " : " << rhs.getElement(i) << endl; 
            } 
            return stream; 
        }
    
    };
    


  • Der Linker weiß nicht, dass die funktion ein template ist, also musst du es ihm sagen. Du musst also

    template <class T> friend ostream& operator <<(ostream& stream, const Array<T>& rhs);
    

    innerhalb der Klasse schreiben und

    template <class T> ostream& operator <<(ostream& stream, const Array<T>& rhs){}
    

    außerhalb der Klasse. Ich habe das doch schon weiter oben berichtigt.

    Edit: Wenn du das template <class T> nicht vor die Funktion innerhalb der Klasse schreibst, dann sucht der Linker nach einer nicht template funktion, die es natürlich dann nicht gibt.



  • So wie du es mir vorgeschlagen hast funktioniert es nicht. Das kann also nicht stimmen .
    Ich belasse es jetzt bei dieser Version.

    #include <iostream>
    using std::ostream;
    using std::endl;
    
    template <class T>
    class Array
    {
        private:
    
            static int defaultsize;
            T *internArray;
            int size;
    
        public:
    
            int getDefaultSize()const; // 
            int getActualSize()const; // 
            void setDefaultSize(int Value); //
            T getElement(int place)const;
            void setElement(T obstacle,int place);
            Array();
            Array(int _size);
            ~Array();
            Array(const Array&);
            Array<T>& operator=(const Array<T>& rhs);
            Array<T> operator+(const Array<T>& rhs);
    
            //STREAM OPERATIONS
            friend ostream& operator <<(ostream& stream,const Array<T>& rhs)
            {
            for ( int i = 0 ; i < rhs.getActualSize() ; i ++) 
            { 
                stream << " Array an Stelle : " << i << " : " << rhs.getElement(i) << endl; 
            } 
            return stream; 
        }
    
    };
    


  • Bei mir geht es.

    #include <iostream>
    
    template <class T> 
    class Array 
    { 
    private: 
    
        static int defaultsize; 
        T *internArray; 
        int size; 
    
    public: 
    
        int getDefaultSize()const;
        int getActualSize()const;
        void setDefaultSize(int Value);
        T getElement(int place)const; 
        void setElement(T obstacle,int place); 
    	Array(){}; 
        Array(int _size); 
    	~Array(){}; 
        Array(const Array<T>&);
        Array<T>& operator=(const Array<T>& rhs);
        Array<T> operator+(const Array<T>& rhs); 
    
        template <class T> 
        friend std::ostream& operator << (std::ostream& stream, const Array<T>& rhs); 
    }; 
    
    template <class T> 
    std::ostream& operator << (std::ostream& stream, const Array<T>& rhs) 
    { 
        stream << "Array"; 
        return stream; 
    }
    
    int main() 
    {
    	Array<int> a;
    	std::cout << a;
    }
    


  • Keine Ahnung was das ist . Ich bekomme diese Fehlermeldung bei deiner Version:

    Undefined symbols for architecture x86_64:
      "operator<<(std::ostream&, Array<int> const&)", referenced from:
          _main in main.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    


  • Da bin ich überfragt... Compiler reparieren? Projekt neu erstellen? Hast du es in einem neuen Projekt versucht?

    Compiler und OS wären eventuell nützlich.



  • Das Problem war einfach dass ich in meiner Operator Definiton nicht wieder T als Platzhalter nutzen darf ...

    LÖSUNG :

    // Sebastian Boldts AAT ( Awesome Array Template )
    #include <iostream>
    template <class T>
    class Array
    {
        private:
    
            static int defaultsize;
            T *internArray;
            int size;
    
        public:
    
            int getDefaultSize()const; // 
            int getActualSize()const; // 
            void setDefaultSize(int Value); //
            T getElement(int place)const;
            void setElement(T obstacle,int place);
            Array();
            Array(int _size);
            ~Array();
            Array(const Array&);
            Array<T>& operator=(const Array<T>& rhs);
            Array<T> operator+(const Array<T>& rhs);
    
            //STREAM OPERATIONS
        template <class U>
        friend std::ostream& operator <<(std::ostream& stream,const Array<U> rhs);
    
    };
    
    /****IMPLEMENTIERUNG****/
    
    template <class T>
    int Array<T>::defaultsize = 10;
    
    template <class T>
    int getDefaultSize()
    {
    
        return Array<T>::defaultsize;
    }
    template <class T >
    int Array<T>::getActualSize()const
    {
        return size;
    }
    
    template <class T>
    void Array<T>::setDefaultSize(int Value)
    {
        Array<T>::defaultsize = Value;
    }
    template <class T>
    T Array<T>::getElement(int place)const
    {
        return internArray[place];    
    }
    template <class T>
    void Array<T>::setElement(T obstacle,int place)
    {   
        if(place < size)
        {
        internArray[place] = obstacle;
        }
    }
    
    //C'toren und D'toren
    
    template <class T>
    Array<T>::Array():size(getDefaultSize())
    {
        internArray = new T[size];
        for (int i = 0 ; i < size ; i ++)
        {
            internArray[i] = 0;
        }
    }
    
    template <class T>
    Array<T>::Array(int _size):size(_size)
    {
        internArray = new T[_size];
        for (int i = 0 ; i < size ; i ++)
        {
            internArray[i] = 0;
        }
    }
    
    template <class T>
    Array<T>::Array(const Array& _array):size(_array.size)
    {
    
        internArray = new T[size];
        for (int i = 0 ; i < size ; i ++)
        {
            internArray[i] = _array.getElement(i);
        }
    }
    template <class T >
    Array<T>::~Array()
    {
    
        free(internArray);
    }
    
    //OPERATOREN
    
    template <class T >
    Array<T>& Array<T>::operator=(const Array<T>& rhs)
    {
        size = rhs.getActualSize();
        delete[]internArray;
        internArray = new T[size];
        for(int i = 0 ; i < size ; i ++)
        {
            internArray[i] = rhs.getElement(i);
        }
        return *this;
    }
    
    template <class T>
    Array<T> Array<T>::operator+(const Array<T>& rhs)
    {
        Array<T> temp(size +rhs.getActualSize());
        for(int i = size ; i < size ; i ++)
        {
            temp.setElement(i) = internArray[i];
        }
        for(int i = size+1 ; i < temp.getActualSize() ; i ++)
        {
            temp.setElement(i) = rhs.getElement(i);
        }
        return temp;
    
    }
    
    template <class U>
    std::ostream& operator <<(std::ostream& stream,const Array<U> rhs)
    { 
        for ( int i = 0 ; i < rhs.internArray[i] ; i ++) 
        { 
            stream << " Array an Stelle : " << i << " : " << rhs.getElement(i) << std::endl; 
        } 
        return stream; 
    }
    
    //#include "ArrayTemplate.cpp"
    
    //...... Coming Soon
    


  • Das ist natürlich logisch. Das sind die Fehler wegen denen man sich oft tot-sucht. 😡
    Immerhin funzt es jetzt 🙂



  • Und nachdem du deinen Quelltext durch den Compiler bekommen hast, kannst du dich als nächstes um die inhaltlichen Fehler kümmern:

    - wenn du Speicher mit new[] anforderst, solltest du ihn auch mit delete[] freigeben und nicht mit free()
    - der Zuweisungsoperator ist nicht gegen Selbstzuweisung geschützt
    - die Anweisung internArray[i]=0; schränkt die Verwandbarkeit der Klasse etwas ein
    - der Vergleich i<rhs.internArray[i] im Ausgabe-Operator ist auch unsinnig

    PS: Außerdem kommt der Ausgabe-Operator komplett mit den öffentlich erreichbaren Teilen des Arrays (getActualSize() und getElement()) aus, also kannst du dir das friend ersparen.

    PPS: Zu den Vorteilen von statischen Methoden und const-Referenzen sage ich jetzt nichts.



  • Ok , dankeschön .
    Werde mich um die Fehler kümmern.


Anmelden zum Antworten