Überladen von []/=



  • So, ich habe jetzt mal versucht deinen Code zu kompilieren (ohne operator[] in MyMap erstmal) aber ich bekomme einige Fehler. Als Anfänger würde ich es begrüßen eine kompilierbare Version von deiner Idee zu bekommen 🙂

    7 [...] ISO C++ forbids declaration of `MyMap' with no type
    14 [...] invalid member function declaration 
    15 [...] `const' qualifiers cannot be applied to `const T&'
    


  • Natürlich muß die siebte Zeile lauten "MyMap<T>& myMap;" - da die Map-Klasse ja ein Template ist. Und bei den Konvertierungsoperatoren fehlen die Klammern "operator T&()" bzw. "operator const T&() const"



  • OK, einen haben wir noch:

    10 [...] expected `)' before '&' token
    

    Ein <T> muss da jedenfalls nicht hin.



  • "MyProxy(MyMap<T>& m, T& v)"

    *nochmal den Code durchsieht* mir fallen jetzt keine Fehler mehr auf


  • Mod

    selbstverständlich muss da <T> hin und ausserdem muss es großgeschrieben werden, denn wir meinen ja das template...



  • Ok, jetzt gehts. Mit <T> hatte es wegen der falschen Groß/Kleinschreibung von MyMap nicht funktioniert.



  • So, ich habe die Proxy-Klasse jetzt eingebaut und alles funktioniert wie gewünscht. Danke!


  • Mod

    operator T&             { return myValue; }
        operator const T& const { return myValue; }
    

    keine gute idee - das führt nähmlich schnell zu mehrdeutigkeiten, ausserdem könnte man den proxy so (scheinbar) umgehen. denn sowohl ein T& als auch ein const T& können gleichermassen benutzt werden um ein T zu erzeugen. die auswahl von benutzerdefinierten konvertierungsoperatoren richtet sich NICHT nach den const-qualifierern des arguments sondern nur nach den argumenten der zielfunktion - alle konvertierungs-operatoren (soweit aufrufbar) sind gleichermassen gut.

    besser:

    operator T const { return myValue; }
    

    und dafür ein const overload für op[] in MyMap das einfach ein T zurückgibt. sobald man mit proxies arbeitet sollte man nirgend mehr referenzen verwenden (höchtens als optimierung). denn ein

    &map[..]
    

    ist dann nicht mehr sinnvoll.



  • camper schrieb:

    und dafür ein const overload für op[] in MyMap das einfach ein T zurückgibt.

    Wie genau sollte es dann aussehen?


  • Mod

    t operator[](const k key) const
    {
        return content[key];
    }
    


  • operator T const { return myValue; }
    

    Das geht so nicht wie ich grade feststelle.

    105 [...] invalid member function declaration
    


  • camper schrieb:

    operator T&             { return myValue; }
        operator const T& const { return myValue; }
    

    keine gute idee - das führt nähmlich schnell zu mehrdeutigkeiten, ausserdem könnte man den proxy so (scheinbar) umgehen. denn sowohl ein T& als auch ein const T& können gleichermassen benutzt werden um ein T zu erzeugen. die auswahl von benutzerdefinierten konvertierungsoperatoren richtet sich NICHT nach den const-qualifierern des arguments sondern nur nach den argumenten der zielfunktion - alle konvertierungs-operatoren (soweit aufrufbar) sind gleichermassen gut.

    Ne, die Lage ist klar.richtig ist, dass beide rückgabewerte gleich gut sind, aber es ist nicht egal, welche der beiden überladungen aufgerufen wird. das const in der 2. methode hat ne große wirkung ;).

    (flugs nochmal getestet)

    struct test{
        int i,j;
        test():i(1),j(2){}
        operator int&(){//klammern net vergessen
            return i;
        }
    
        operator const int&()const{//dito
            return j;
        }
    };
    int main(){
        test t;
        cout<<t<<endl;
    	cout<<const_cast<const test&>(t);
    	int i;
    	cin>>i;
    }
    

    ausgabe: 1 2


  • Mod

    hm ja, stimmt - hatte mal ein problem mit solchen overloads, aber das war doch noch ein bisschen anders. ich bleibe aber dabei, dass es keine gute idee ist, referenzen auf interna eines proxies herauszugeben, da das dem zweck des proxies doch irgendwie zuwiderläuft. und mit konvertierungs-operatoren sollte man sowieso sehr vorsichtig umgehen.



  • du musst ja nicht interna des proxys zurückgeben, sondern interna des objekts, vor das sich der proxy vorschaltet ;).



  • Nachdem ich jetzt etwas weitergemacht habe, gibt es aber doch noch ein Problem. Beispielsweise geht folgendes nicht:

    umap<string, umap<string,string> > test;
    test["foo"]["bar"] = "test";
    

    Auch das nicht:

    struct t {
    	string foo;
    	string bar;
    };
    
    umap<string,t> test2;
    test2["foo"].foo = "test";
    

    Diese Funktionalität ist mir aber von äußerster Wichtigkeit. Also was tun?



  • und _was_ geht nicht?



  • Alles bis auf das Deklarieren geht nicht.

    30 [...] 'class MyProxy<std::string, t>' has no member named 'foo'
    


  • ist ja auch klar, dass es nicht geht. die konvertierungsoperatoren treten nur in kraft, wenn der compiler weis, dass er konvertieren muss. So schaut er nur, ob MyProxy eine variable foo hat.

    also konvertierst du entweder von hand mithilfe eines casts, doer lässt dir was einfallen.

    möglichkeit 0:
    einfach casten:

    static_cast<t>(test2["foo"]).foo
    

    möglichkeit 1:
    eine get methode einbauen. dann sieht es so aus:

    test2["foo"].get().foo
    

    möglichkeit 2:
    überladen des op->

    test2["foo"]->foo
    


  • otze schrieb:

    also konvertierst du entweder von hand mithilfe eines casts, doer lässt dir was einfallen.

    Also das "lässt dir was einfallen" wollte ich eigentlich euch überlassen 😃

    möglichkeit 0:
    einfach casten:

    static_cast<t>(test2["foo"]).foo
    

    Funktioniert, macht den Code aber nicht grade schöner.

    möglichkeit 1:
    eine get methode einbauen. dann sieht es so aus:

    test2["foo"].get().foo
    

    möglichkeit 2:
    überladen des op->

    test2["foo"]->foo
    

    Das geht für meinen ersten Fall

    test["foo"]["bar"] = "test";
    

    aber nicht, oder?


  • Mod

    otze schrieb:

    du musst ja nicht interna des proxys zurückgeben, sondern interna des objekts, vor das sich der proxy vorschaltet ;).

    womit der proxy sich selbst ausschaltet - ich dachte der zweck des proxies wäre gerade, den zugriff auf diese interna zu maskieren.
    original:

    struct X
    {
        // ...
        int& operator[](size_t i) { return data[i]; }
    };
    void foo(int&)
    {
    // ...
    }
    void bar()
    {
       X x;
       foo(x[1]);
    }
    

    jetzt mit proxy:

    struct X
    {
        struct Proxy
        {
            // ...
            int& ref_;
            operator int&() { return ref_; }
        };
        // ...
        Proxy operator[](size_t i) { return Proxy(data[i]); }
    };
    void foo(int&)
    {
    // ...
    }
    void bar()
    {
       X x;
       foo(x[1]);
    }
    

    ups, das kompiliert ja immer noch... und dabei wollten wir doch einen proxy damit wir bei veränderungen noch ein bisschen extra arbeit erledigen können.


Anmelden zum Antworten