c# style [] operator



  • Sowas in der Richtung habe ich schon, nur nicht als rückgabewert für operator[].
    Weil ich dieses ewige leidige getXY, setXY einfach satt habe habe ich mir kurzerhand accessor<> gebastelt.

    Diese nimmt einen Pointer auf einen Klassenmember und ein Flag für den Zugriff, eventuell kann ich da etwas ableiten oder so umbauen, dass ich tatsächlich sowas mit relativ wenig Aufwand realisieren könnte (ein Pointer ist ein minimales übel)



  • @krümelkacker
    Wozu dann überhaupt noch über operator[] gehen - da kann man gleich die Accessor-Klasse als public Member machen.
    Dann muss man nur mehr obj.foo = 99; schreiben. Und verpestet den global-namespace nicht.

    ps: Dass man dafür mit einem etwas aufgeblähten Objekt bezahlt ist klar. Ist halt die Frage ob die ganzen Zeiger wirklich stören. Bzw. wenn man unbedingt will könnte man sogar vom "this" des Accessor-Members auf das "this" des äusseren Objekts zurückrechnen. Ist zwar vielleicht "pfui", aber funktioniert sicher problemlos.



  • Pria schrieb:

    Sowas in der Richtung habe ich schon, nur nicht als rückgabewert für operator[].
    Weil ich dieses ewige leidige getXY, setXY einfach satt habe habe ich mir kurzerhand accessor<> gebastelt.

    Diese nimmt einen Pointer auf einen Klassenmember und ein Flag für den Zugriff,

    Ich dachte, du willst irgendwelche C-Funktionen für's Setten und Getten aufrufen. Wenn du doch schon ein passendes Datenelement zur Hand hast, was macht dann dein accessor anderes als eine Referenz?



  • krümelkacker schrieb:

    Ich dachte, du willst irgendwelche C-Funktionen für's Setten und Getten aufrufen.

    Ich will nicht, ich muss und der accessor ist mommentan "nur" darauf ausgelegt einen datenpointer auf eine member variable zu halten.
    Ich überlege mir gerade ob es nicht sinnvoller wäre tatsächlich komplett auf set und get methoden zu gehen und den accessor quasi als wrapper nach aussen zu benutzen.



  • Kannst du ein moeglichst einfaches aber komplettes Beispiel als Code posten?

    Ich wuerde es ja genau andersherum machen. Einen Modifier schreiben, der das Objekt als Parameter bekommt und auf diesem arbeitet.



  • Die accessorklasse (hier full-access) die ich derzeit verwende, natürlich deutlich verbesserungswürdig. Eventuell geh ich hier tatsächlich komplett auf set, get, methoden, auch wenn dies bedeutet, dass der Anwender dann noch zusätzlich 2 methoden haben muss oder ich biete es optional über eine spezialisierung an.

    template<typename T>
    	struct accessor<void,T,AccessorFlag::FullAccess>
    	{
    		T &ptr;
    
    		public:
    			accessor(T &ptr) : ptr(ptr){}
    
    			inline T get() {return ptr;}
    			operator T() {return (T) this->ptr;}
    			inline T operator() () { return ptr; }
    			inline T* operator-> () {return &ptr;}
    
    			inline void operator =(T value) {ptr = value;}
    			inline void operator() (T value) { ptr = value; }
    			inline void set(T value) {ptr = value;}
    	};
    

    Der indexer, den ich gerade mal eben hingerotzt habe

    template<class O, typename Index, typename T, void (O::*set) (Index, T), T (O::*get) (Index)>
    	struct indexer
    	{
    		O* owner;
    		Index index;
    
    		public:
    			indexer(Index index) : index(index) {};
    
    			inline T get() { return owner->get(index); }
    			operator T() { return (T) owner->get(index); }
    			inline T operator() () { return owner->get(index); }
    
    			inline void operator =(T value) { owner->set(index, value); }
    			inline void operator() (T value) { owner->set(index, value); }
    			inline void set(T value) { owner->set(index, value); }
    	};
    

    Die Schnittstellenfunktion sieht so aus

    void* GetParameter(const char* index);
    void SetParameter(const char* index, void* value);
    

    [EDIT]
    Wobei void* jeweils einen von 4 standarddatentypen int, double, float, short haben kann



  • Und wie benutzt du das ganze? Wie sieht eine minimale main-Fkt. aus? Bzw. wie sieht das aus, was du erreichen willst. Tut mir leid, mit C# kann ich nichts anfangen (und 'wie C#' ist demnach nichtssagend). Davon mal abgesehen, in C++ wird eben nicht wie in C# programmiert.



  • na ganz einfach, die accessoren in eine klasse packen

    class X
    {
       public:
          X() : MyInt(myInt) {}
          accessor<int, AccessorFlag::FullAccess> MyInt;
    
       private myInt;
    }
    
    main()
    {
       X xy;
       xy.MyInt = 20;
       int v = xy.MyInt;
    }
    

    Was ich über den Indexer erreichen möchte ist schlicht folgendes, wie es mittlerweile bei vielen Sprachen Standard ist

    class IndexerText
    {
       public:
         indexer<string, int, &GetParameter, &SetParameter> operator[] (string index)
         {
            indexer<string, int, &GetParameter, &SetParameter> i(index);
            return index;
         } 
    
       /*
       in c#
       int this[string index]
       {
          get{ return GetParameter(index); }
          set{ SetParameter(index, value); }
       }
       */
    }
    
    main()
    {
       IndexerTest t;
       t["test"] = 20;
       int v = t["test"];
    }
    

    btw. ich habe gerade mal (vergeblich) versucht die templates so zu ändern, dass ich lediglich über die parameteranzahl der argumente zwischen funktion und direktzugriff wechsel, hat allerdings nicht geklappt. Kann mir jemand sagen wie ich volgendes dilemma auflösen kann

    template<typename T, class O, void (O::*setPtr) (T), T (O::*getPtr) ()>
    	struct accessor
    	{
    		O* owner;
    
    		public:
    			_access(O* owner) : owner(owner){}
    
    			inline T get() {return (owner->*getPtr)();}
    			operator T() {return (T) (owner->*getPtr)();}
    			inline T operator() () { return (owner->*getPtr)(); }
    			inline T* operator-> () {return &(owner->*getPtr)();}
    
    			inline void operator =(T value) {(owner->*setPtr)(value);}
    			inline void operator() (T value) { (owner->*setPtr)(value); }
    			inline void set(T value) {(owner->*setPtr)(value);}
    	};
    
    	template<typename T>
    	struct accessor<T, void, NULL, NULL> //<- compiler error
    	{
    		T &ptr;
    
    		public:
    			_access(T &ptr) : ptr(ptr){}
    
    			inline T get() {return ptr;}
    			operator T() {return (T) this->ptr;}
    			inline T operator() () { return ptr; }
    			inline T* operator-> () {return &ptr;}
    
    			inline void operator =(T value) {ptr = value;}
    			inline void operator() (T value) { ptr = value; }
    			inline void set(T value) {ptr = value;}
    	};
    


  • Probier mal so (ungetestet)

    class DummyClass {};
    
    template<typename T>
    struct accessor<T, DummyClass, (void (DummyClass::*)(T)) 0, (T (DummyClass::*)()) 0>
    {
        T &ptr;
    
    ...
    

    Bzw. vermutlich sind die Casts nichtmal nötig.
    DummyClass ist aber sicher nötig, weil void kann nicht der Klassentyp eines Member-Function-Pointers sein.

    Ich würde aber eher ein eigenes Template verwenden.



  • Klappt leider immer noch nicht

    error C2754: 'accessor<T,DummyClass,0x0,0x0>': Eine teilweise Spezialisierung darf keinen abhängigen Nichttyp-Vorlagenparameter haben
    

    Ich würde aber eher ein eigenes Template verwenden.

    ich würds der Einfacheit halber gerne in ein und dem selben objekt anbieten wollen

    [Edit]

    Habe es nun nach ein wenig rumprobieren und etwas tricksen hingekriegt, sogar so, dass ich jetzt sämtliche Zugriffstypen und evtl. sogar den indexer drüber laufen lassen kann.

    template<typename T> struct _setget{};
    template<typename T, class O, void (O::*setPtr) (T), T (O::*getPtr) ()> struct _setgetf{};
    
    template<class A, long I> //<- alibi variable
    struct accessor;
    
    template<typename T, class O, void (O::*setPtr) (T), T (O::*getPtr) ()>
    struct accessor<_setgetf<T,O,setPtr,getPtr>,0>
    { ... };
    
    template<typename T>
    struct accessor<_setget<T>,0>
    { ... };
    

    und verwende dies im code nun folgendermaßen

    class X
    {
      public:
          X() : XY(xy) {}
          accessor<_setget<int>,0 /*muss leider sein, evtl per macro ersetzen*/ > XY;
    
      private:
          int xy;
    };
    
    main()
    {
       X x();
       x.XY = 20;
       cout << x.XY << endl;
    }
    

Anmelden zum Antworten