Macro für Attribute iterierbar machen?



  • Hallo,

    ich will mit Hilfe von Macros es dem Nutzer einer Klasse vereinfachen, Attribute zu dieser Klasse hinzuzufügen. Das mache ich so:

    #define ATTRIBUTE(name) \
        int value##name; \
        int get##name() { return value##name; } \
        void set##name(int val) { value##name = val; }
    
    struct Data
    {
        ATTRIBUTE(First)
        ATTRIBUTE(Second)
        ATTRIBUTE(Third)
    };
    
    int main()
    {
        Data data;
        data.setFirst(1); // etc.
    }
    

    Das geht auch soweit ganz gut. Allerdings bräuchte ich jetzt noch eine Memberfunktion in Data , die etwas mit allen so generierten Attributen macht, zum Beispiel diese in einen String konvertiert und zusammennhängt.

    Deswegen meine Frage, gibt es eine Möglichkeit so erzeugte Attribute "iterierbar" zu machen? Also dass ich in der Memberfunktion über diese loopen kann ohne jedes Attribut wieder explizit mit Namen anzusprechen?



  • Hi,

    a) finde ich das wirklich hässlich, was du vorhast. Es spart evtl. ein bissel Tipparbeit, aber trägt definitiv nicht zur Lesbar- und Wartungsfreundlichkeit bei.

    b) gehen tut das mit dem drüber iterieren. Dann Packst du dir in deine Klasse noch einen statischen Vektor und fügst mit deinem Makro auch automatisch einen neuen Eintrag in diesen Vektor hinzu. Et voila ... du kannst über deine Attribute drüber iterieren.



  • MakroIterator schrieb:

    Hi,

    a) finde ich das wirklich hässlich, was du vorhast. Es spart evtl. ein bissel Tipparbeit, aber trägt definitiv nicht zur Lesbar- und Wartungsfreundlichkeit bei.

    Naja, Geschmacksache. Ist halt hier das geringste Übel und zum Verstehen bezüglich Lesbarkeit finde ich das eigentlich recht intuitiv.

    MakroIterator schrieb:

    b) gehen tut das mit dem drüber iterieren. Dann Packst du dir in deine Klasse noch einen statischen Vektor und fügst mit deinem Makro auch automatisch einen neuen Eintrag in diesen Vektor hinzu. Et voila ... du kannst über deine Attribute drüber iterieren.

    Aber wie soll das gehen, das ist ja grade die Frage.

    In dem Macro kann ich ja nichts in einen Vector einfügen, dafür bräuchte ich ja eine eigene Funktion. Selbst wenn ich per Macro für jedes Attribut eine "füge-dieses-attribut-in-den-Vector-ein"-Funktion generieren lasse, muss diese Funktion ja immer noch von irgendwoher gecallt werden.



  • Dann musst du in deinen Klassen auch Standardmässig einen Vector mit überall dem gleichen Namen reinpacken.

    #define ATTRIBUTE_HANDLED_CLASS static std::vecotr myAttributes;
    
    struct Data
    {
        ATTRIBUTE_HANDLED_CLASS
        ATTRIBUTE(Data, First)
        ATTRIBUTE(Data, Second)
        ATTRIBUTE(Data, Third)
    };
    

    und dein Makro diesbezüglich erweitern. Irgendwie so, hätte ich mir das gedacht:

    #define ATTRIBUTE(class, name) \
        int value##name; \
        int get##name() { return value##name; } \
        void set##name(int val) { value##name = val; } \
        ##class::myAttributes.pushback(#name);
    

    Oben das ist ungetestet ... aber so solltest du schon mal meine Idee dazu verstehen ... hoffe ich!



  • happystudent schrieb:

    Naja, Geschmacksache. Ist halt hier das geringste Übel und zum Verstehen bezüglich Lesbarkeit finde ich das eigentlich recht intuitiv.

    Das ist nicht wirklich lesbarer als:

    struct Data
    {
        int first;
        int second;
        int third;
    };
    

    Aber jedenfalls kannst du einen Funktionsaufruf beispielsweise so tätigen:

    int value##name=registerAttribute(&value##name);
    


  • MakroIterator schrieb:

    Oben das ist ungetestet ... aber so solltest du schon mal meine Idee dazu verstehen ... hoffe ich!

    Ich glaube du hast das Problem nicht ganz verstanden.

    Ersten muss (und soll) der Vector nicht static sein, schließlich will ich mehrere Instanzen der Klasse nutzen. Und zweitens kann man auf Klassenebene eben keine Funktionen aufrufen, deswegen geht dein Code nicht.

    ;qwerty schrieb:

    Das ist nicht wirklich lesbarer als:

    Ist auch nur ein Minimalbeispiel welches aufs wesentliche reduziert ist. In der echten Klasse ist das komplexer und macht deswegen auch Sinn.

    ;qwerty schrieb:

    Aber jedenfalls kannst du einen Funktionsaufruf beispielsweise so tätigen:

    int value##name=registerAttribute(&value##name);
    

    Ok, das sieht gut aus, so einen Trick hab ich gesucht.

    Ich frage mich nur gerade ob das auch erlaubt ist? Darf ich die Addresse von value##name in dessen Initialisierung benutzen oder ist das UB?


Anmelden zum Antworten