Fehlender "==" Operator Fehler, obwohl vorhanden



  • Hi,

    ich hab das Gefühl, dass mich C++ verarscht. Ich muss den "==" Operator meiner Klasse überladen, da ich ein vector damit fülle und std::find() ausführen will. Obwohl ich dies gemacht habe, beschwert sich der Kompiler über den fehlenden Operator. Das Beispiel Projekt, welches ziemlich ähnlich aufgebaut ist, lässt sich natürlich problemlos kompilieren und ausführen. Wie passt das zusammen, was mache ich falsch?

    Hier der Header:

    #pragma once
    
    //#include "GraphicsContext.h"
    
    namespace gl
    {
    	class Buffer
    	{
    	protected:
    		GraphicsContext& context;
    		void* data;
    		bool locked;
    	public:
    		Buffer(GraphicsContext& context, unsigned dataSize);
    		virtual ~Buffer();
    
    		void* Lock();
    		void Unlock();
    
    		bool Equal(const Buffer& other) const;
    		//bool operator ==(const Buffer& op2) const;
    	};
    
    	bool operator==(const gl::Buffer& lhs, const gl::Buffer& rhs);
    }
    

    Hier die Methode welche std::find ausführt:

    void GraphicsContext::RegisterBuffer(Buffer& buf)
    	{
    		auto iter = std::find<std::vector<Buffer*>::iterator>(buffers.begin(), buffers.end(), buf);
    		if (iter != buffers.end())
    			buffers.push_back(&buf);
    	}
    

    Der Fehler:

    Fehler	1	error C2679: Binärer Operator '==': Es konnte kein Operator gefunden werden, der einen rechtsseitigen Operanden vom Typ 'const gl::Buffer' akzeptiert (oder keine geeignete Konvertierung möglich)	c:\program files (x86)\microsoft visual studio 11.0\vc\include\xutility	3186	1
    

    Das Beispielprojekt:

    #include <iostream>
    #include <memory>
    #include <vector>
    #include <iterator>
    #include <algorithm>
    
    using namespace std;
    
    namespace tl
    {
    class A
    {
    private:
        int a, b;
    public:
    	A() {}
        A(int a, int b)
        {
            this->a = a;
            this->b = b;
        }
    
        bool equal(const A& other) const
        {
            if (a == other.a || b == other.b)
                return true;
            return false;
        }
    };
    
    bool operator==(const tl::A& a, const tl::A& b)
    {
        return a.equal(b);
    }
    
    class B : public A
    {
    public:
    	B(int a, int b) : A(a, b) {}
    };
    
    }
    
    tl::B readB()
    {
        int a, b;
        cout << "A a: ";
        cin >> a;
        cout << " | b: ";
        cin >> b;
        cout << std::endl;
        return tl::B(a, b);
    }
    
    int main()
    {
        tl::B t1 = readB();
        tl::B t2 = readB();
    
        cout << (t1 == t2) << endl;
    
        vector<tl::A> vec(2);
        vec.push_back(t1);
        vec.push_back(t2);
    
        auto iter = find<vector<tl::A>::iterator>(vec.begin(), vec.end(), t2);
        if (iter != vec.end())
            cout << "Founded!";
        else
            cout << "Not founded";
    
        std::cin.get();
    }
    

    Ich benutze Visual Studio 2012. Ich hoffe die Definitionen reichen, wenn nicht gibts den Quellcode auch.
    Vielen Dank!



  • Bitte die Fehlermeldung umformatieren, ich möchte nicht immer 300000000 Meter nach rechts scrollen mit dem Browser um was zu lesen.

    Zum Problem: Dein Operator== erwartet einen Buffer, bzw eine Referenz darauf, was syntaktisch beim Aufruf dasselbe ist.

    Dein vector hält aber Zeiger auf Buffer Objekte (allein schon wegen den zeigern böse!). Der sucht nun also nach einem operator==(Buffer *, Buffer 😉 bzw operator==(Buffer *, Buffer&)

    Und wieso lässt du den Compiler die Typen der find Funktion nicht selsbt herleiten?!



  • Skym0sh0 schrieb:

    Bitte die Fehlermeldung umformatieren, ich möchte nicht immer 300000000 Meter nach rechts scrollen mit dem Browser um was zu lesen.

    Oh das wusste ich nicht, keine Absicht. Kann ich leider auch nicht ändern, da ich nicht angemeldet bin, kann ein Moderator vielleicht aushelfen?

    Danke für die Erklärung, ich dachte es gäbe nur einen Operator mit Referenzen. Jetzt klappts!

    Skym0sh0 schrieb:

    Dein vector hält aber Zeiger auf Buffer Objekte (allein schon wegen den zeigern böse!).

    Ich weiß, der Kompiler hat wegen irgendwas gemeckert, als ich eine Referenz benutzen wollte. Das muss ich wohl nochmal versuchen.



  • Referenzen kannst du nicht in Listen Speichern, weil sie beim Erzeugen direkt initialisiert werden müssen <--> widerspricht Listen

    Rohe Zeiger in Listen (sei es Arrays, Vectoren oder Bäume) sind nicht zu empfehlen, da du die "gezeigten" Objekte manuell löschen musst oder umgekehrt dafür sorgen musst, dass die referenzierten Objekte nicht zu früh gelöscht werden.

    Wenn dein vector also den alleinigen Besitz der Objekte innehat, dann nimm std::vector<std::unique_ptr<Buffer>> (oder boost::ptr_vector<Buffer>), wenn die Objekte woanders gehalten werden nimm statt unique_ptr shared_ptr oder weak_ptr je nachdem...



  • Zuerst wollte ich das mit shared_ptr lösen, dann jedoch habe ich gemerkt, dass das vielleicht nicht ideal ist, deshalb habe ich im Forum nachgefragt.
    http://www.c-plusplus.net/forum/314925
    Dort wurde mir geraten, das ganze zu vereinfachen, weshalb ich dann auf die Zeiger umgestiegen bin. Doch das ist nicht die Lösung.
    Eigentlich wollte ich das so machen, dass der Buffer selbst erstellt werden kann, sich dieser dann beim GraphicsContext anmeldet und von iohm verwaltet wird,
    jedoch soll man auch in der Lage sein den Destruktor des Buffers selbst aufzurufen. Der Buffer meldet sich dann beim GraphicsContext ab.
    Wenn ich mir das so ansehe, wäre ein shared_ptr dann doch angebracht, oder? Schließlich kann der Buffer vom Benutzer sowohl auch vom GraphicsContext gelöscht werden.

    Ein Factory-Pattern würde mir sonst noch einfallen, manchmal muss man einfach einen Kompromiss eingehen.
    Obwohl mir das Pattern in C++ nicht so gefällt, in C# lässt sich sowas besonders elegant machen.



  • Naja, das sind verschiedene Dinge, die du haben willst.

    Dass du deine Buffer speichern willst/musst ist keine Frage, aber dazu gehört dann auch, dass sie gelöscht werden, wenn sie wegsollen. Das ist am einfachsten und am sichersten mit Smart-Pointern zu lösen, wie gesagt unique_ptr.

    Dass sich deine Buffer irgendwo an- oder abmelden ist ein anderes Problem. Und deinen Buffer sollte es auch eigentlich nicht interessieren, wo er gelagert oder registriert ist, da dies die Abhängigkeit signifikant erhöht. Er ist halt semantisch nicht korrelierend mit dem GraphicsContext.

    Das GoF-Factory-Pattern würde ich hier nicht nehmen, eher sowas:

    class Buffer
    {
    public:
        Buffer(int x /*, und andere Parameter*/);
        // .....
    };
    
    std::shared_ptr<Buffer> createBuffer(std::vector<std::shared_ptr<Buffer>> & contextList, int x /*, und deine anderen CTor Parameter*/)
    {
        std::shared_ptr<Buffer> tmp(new Buffer(x, ...));
        contextList.push_back(tmp);
        return tmp;
    }
    

    Du kapselst so den Construktor ab, aber hängst deine Bedingungen dran (halt, dass dein objekt direkt in eine Liste geshcoben wird)



  • Wäre das nicht eine Factory? Jedenfalls, so denke ich, in meinem Fall, denn Buffer ist eigentlich nur die Basisklasse für FrameBuffer, VertexBuffer, ... .

    Das heißt das GraphicsContext so aussehen würde?

    class GraphicsContext
    {
    private:
    	std::vector<std::shared_ptr<Buffer>> buffers;
    	//...
    public:
    	std::shared_ptr<FrameBuffer> createFrameBuffer(/* ... */)
    	{
    		std::shared_ptr<FrameBuffer> tmp(new FrameBuffer(/* ... */));
    		buffers.push_back(tmp);
    		return tmp;
    	}
    	std::shared_ptr<VertexBuffer> createVertexBuffer(/* ... */);
    	//...
    };
    


  • Eventuell würde ich die Methoden hier rauslösen und sie entweder in einer statischen Klasse (halbwegs kontextfrei) unterbringen oder sogar direkt frei machen.

    Nein, das Factory-Method Pattern macht was anderes, der Wikipedia Artikel sit da ganz gut...



  • Alles klar. Jetzt hab ichs verstanden, vielen Dank für deine Hilfe. Bin schon ewig an dieser Designfrage gesessen. 👍


Log in to reply