lhs/rhs Unterscheidung dank Operator () Überladung?
-
Man nennt das auch Proxy.
Ist in (fast?) jeder vector<bool> Implementierung zu finden, und der Grund warum vector<bool> immer (fast immer?) ein "Spezialfall" ist, weil andere Regeln dafür gelten.
z.B. geht dann sowas nimmer (was mit jedem anderen Typ ausser bool funktioniert):bool& b = vec[123]; b = false;Den selben Effekt hast du dann auch, wobei das nicht negativ sein muss - gehört halt nur dokumentiert.
-
hustbaer schrieb:
Man nennt das auch Proxy.
Ist in (fast?) jeder vector<bool> Implementierung zu finden, und der Grund warum vector<bool> immer (fast immer?) ein "Spezialfall" ist, weil andere Regeln dafür gelten.
z.B. geht dann sowas nimmer (was mit jedem anderen Typ ausser bool funktioniert):bool& b = vec[123]; b = false;Deshalb benutzt man std::vector<bool>::reference statt bool&

-
um nochmal zum eigentlichen Thema zurückzukommen:
Es funzt, teilweise.
Leider aber eben nicht völlig transparent, ein Beispiel:
Graph<Klasse*> g; g(2,4) = new Klasse(); g(2,4)->irgendnefunktion(); // FEHLER: "Basisoperand von »->« hat Nicht-Zeiger-Typ »Graph<Klasse*>::foo<Klasse*>"Ich nehm mal an ich muss für die Proxy Klasse auch den Operator -> definieren? Am besten noch gleich den . Operator. Aber nach ausführlicher Suche im inet nix dazu gefunden. Kann mir wer helfen?
-
LudiKalell schrieb:
Ich nehm mal an ich muss für die Proxy Klasse auch den Operator -> definieren? Am besten noch gleich den . Operator. Aber nach ausführlicher Suche im inet nix dazu gefunden. Kann mir wer helfen?
Den '.'-Operator kannst du nicht deklarieren, nur den "->"-Operator (
T* operator->();). Du musst dir halt nur überlegen, wie du das behandelst.
-
Am einfachsten wäre es (da der Proxy ja nur für einen einzigen Typen eingesetzt wird) die entsprechenden Methoden als Weiterleitung in der Proxyklasse zu implementieren:
class Bla { class TollerProxy { public: void abgefahrene_methode () const { BlaZeiger->getValue(bla, bla).abgefahrene_methode(); } //... }; //... };
-
Ok habs gefunden..
T operator ->() const { return graph->getWeight( a, b); }Ok den . Operator kann ich nicht überladen..
Folgendes CodebeispielGraph< pair <double,double> > g; g(2,4) = pair<double, double>(3, 4); g(2,4).first = 3; // "Fehler: »class Graph_UW<std::pair<double, double> >::foo<std::pair<double, double> >« hat kein Element namens »first«Irgend ne Möglichkeit das zu maskieren bzw ihn zu zwingen ZUERST zu casten und dann . zu verwenden?
Und gerade noch ein Problem gefunden mit
Graph< baseclass* > g(10,NULL); dynamic_cast<derived_class*>(g(2,4))->some_member_of_derived_class(); //"Fehler: ungültiges dynamic_cast vom Typ »Graph<baseclass*>::foo<baseclass*>« in den Typ »derivedclass*«Wenn ich das umschreibe als
baseclas* b = g(2,4); dynamic_cast<derived_class*>(b)->some_member_of_derived_class();funzt es natürlich. Wenn ich das ganz am Beispiel von static_cast<double>(Graph< int >) mache nörgelt er nicht.
Edit:
Das passiert wenn man zu lange am Text schreibt
danke..
Und nein, der Proxy wird leider jetzt schon für 3 verschiedene Typen eingesetzt und soll so in eine Bibliothek übernommen werden. Dafür natürlich möglichst transparent. Mit den bald mal im C++ Standrad aufgenommenen template "Abfragen" könnte man vielleicht zwischen pointer und normalem Typ unterscheiden, aber derzeit ist das wirklich hässlich.
-
LudiKalell schrieb:
Irgend ne Möglichkeit das zu maskieren bzw ihn zu zwingen ZUERST zu casten und dann . zu verwenden?
Ich glaube das mit dem casten hast du nicht ganz verstanden.. Wenn du mit
g(2,4)=...drauf zugreifst, wird nichts gecastet, es wird einfach nur der operator= aufgerufen, der die rechte Seite des Gleich-Zeichens übergeben bekommt und die setXXX-Methode des Graphen aufruft.LudiKalell schrieb:
g(2,4).first = 3;Nochmal: Den Operator "Punkt" kannst du nicht überladen, die Proxy-Klasse hat keinen Member namens "first", deshalb klappt auch
g(2,4).blanicht! Wenn du den Pfeil-Operator gut überladen hast, kannst du mitg(2.4)->first += 1389;drauf zugreifen, dafür ist er ja da.
-
Ich hab meinen text vom letzten Post nur stehen lassen, siehe edit, hatte deinen Text gelesen.
Ja dass bei dem Beispiel nur der Zuweisungsoperator ne Rolle spielt hab ich übersehn. Hatte das mit dem cast etc. schon cverstanden, ich hab überall couts gesetzt und seh welche Funktion wann aufgerufen wird für verschiedene Szenarien weil ich mir anfangs nich sicher war.Dennoch: Ich benutze den Graphen für Pointer genauso wie für normale Objekte. Demzufolge
T operator->() const
Dieser hat die erwünschte Auswirkung für Pointer Objekte. Man muss nicht wissen dass da ein Pointer dahintersteckt. Und ich benutz sehr oft Pointer..
Die Verwendung ist also transparent. Für normale Objekte gibts dann den Compilefehler.. Nagut, ich könnte.. hrmm..
T operator->() const
zusätzlich überladen. Und definieren dann operator ->() eben nen T zurückgibt.
Dann bei Pointer ->* benutzen und sonst statt . nen ->()Ne bessere Lösung möglich?
edit: oder ich schreib 2 Varianten, eine für Pointer, eine für Objekte, und überprüfe im Constructor irgendwie dass sie entsprechend falsch verwendet werden. Was aber glaube ich nicht geht.. obwohl.. doch.
Müsste ja im Construktor schon nen this haben und damit mal probeweise son -> operator anwenden, dann sollte der Compiler missbrauch verbieten.
-
Gut ich lege das Problem lieber bei Seite. Es scheint keine wirklich gute Lösung zu geben für den . Operator wenn man Transparenz möchte. Hab nun ne at() Funktion für den speziellen Fall.
Aber dann bleibt immer noch folgendes evtl. lösbares Problem:
Graph< baseclass* > g(10,NULL); baseclass* b; dynamic_cast<derived_class*>(g(2,4))->some_member_of_derived_class(); //"Fehler: ungültiges dynamic_cast vom Typ »Graph<baseclass*>::foo<baseclass*>« in den Typ »derivedclass*« dynamic_cast<derived_class*>(b = g(2,4))->some_member_of_derived_class(); //funzt!Das passiert auch mit C cast, static_cast, reinterpret_cast, ...
-
Den ->* Operator kannst Du auch nicht überladen, ausserdem sähe das vermutlich syntaktisch gräßlich aus

Über Spezialisierung wäre sowas machbar:
template<class T> // macht aus T einen zeiger für alle nicht-zeigertypen struct graph_pointer_helper { typedef T* type; static type pointer( T& value ) { return &value; } }; template<class T> // spezialisierung für zeiger reicht nur durch struct graph_pointer_helper<T*> { typedef T* type; static type pointer( T* value ) { return value; } }; template<class T> class Graph { public: explicit Graph( T const& value = T() ) : value( value ) {} typename graph_pointer_helper<T>::type operator->() { return graph_pointer_helper<T>::pointer( value ); } private: T value; }; int main() { Graph<string> a; a->assign( "hallo" ); Graph<string*> b( new string ); b->assign( "hallo" ); }
-
LordJaxom schrieb:
Den ->* Operator kannst Du auch nicht überladen
Ich denke, das ist möglich...
-
Naja ->* ist schon überladbar, sagt MSDN, das inet und auch mein Compiler

Ja der Code sieht schön aus, nur leider halt Spezialisierung, der Graph soll wie gesagt alles möglich an verschiedenen Klassenpointern nehmen(gut das ist nicht das Problem, da funzt T operator->() ja einwandfrei und transparent) und eben auch noch Objekte. Gut für die Objekte könnte man dann ne Spezialisierung einfügen, aber so wie ich das verstehe muss ich die Spezialisierung dann auch für alle Pointertypen definieren.
Und selbst wenn nicht: es soll einfach funktionieren, für jeden Typen.Ich habe glaube mittlerweile eine zumindest für mich befriedigende Lösung gefunden:
Da der Anwender eh schonmal so oder so nicht drum rumkommt die Klasse wenigstens etwas zu kennen (-> für jeglichen Memberzugriff und kein operator. erlaubt oder ähnliches) hab ich einfach folgendes festgelegt:const T& operator() (size_t,size_t) foo<T>& operator [](size_t a) foo<T>& foo<T>::operator [](size_t B) {b = B; return *this;} T& at(size_t) // Schreibzugriff: g[i][j] = x; // Lesezugriff: x = g(i,j); // cast: x = static_cast<class*>(g(i,j)); //Memberzugriff wenn T Pointertyp g[i][j]->blub(); //Memberzugriff wenn T kein Pointertyp g(i,j).blub(); //wenn blub() const g.at(i,j).blub(); //sonstIst zwar an der Grenze der Transparenz, aber da der User eh den header anschaun muss noch ok..
Wenn sonst keine weiteren Vorschläge kommen dann nochmal
DANKE DANKE DANKE
an alle und vor allem an Badestrand
-
LudiKalell schrieb:
Ja der Code sieht schön aus, nur leider halt Spezialisierung, der Graph soll wie gesagt alles möglich an verschiedenen Klassenpointern nehmen(gut das ist nicht das Problem, da funzt T operator->() ja einwandfrei und transparent) und eben auch noch Objekte. Gut für die Objekte könnte man dann ne Spezialisierung einfügen, aber so wie ich das verstehe muss ich die Spezialisierung dann auch für alle Pointertypen definieren.
Und selbst wenn nicht: es soll einfach funktionieren, für jeden Typen.Tut es doch, die Spezialisierung spezialisiert ja nur für Pointer. Für alle anderen Typen gilt das Basistemplate. Einschränkungen auf einen bestimmten Typ sehe ich hier nicht.
-
Spezialisierung für Pointer wäre grauenhaft. Wir verwenden alle möglichen Basispointer und Pointer auf Subklassen, und es kommt noch Kram dazu. Locker 10 Spezialisierungen wären da nötig, und der Code bläht sich auf, evtl. auch die Compilezeit? Naja ich behalt's mal im Kopf, vielleicht ist das am Ende die beste Lösung.