Variadic Macros mit Concatenation benutzen



  • @Wutz Achso nein ich möchte auch keine Typen übergeben, sondern nur int. Der "Type_" Prefix war nur irgendein Beispiel für etwas, das man vor jedes Argument stellen möchte. Um etwas klarer zu machen, was ich meine, zeige ich mal ein Beispiel, wie man es nutzen können sollte.

    #define PositionFooBar 1
    #define VelocityFooBar 2
    
    typedef struct
    {
        int x, y;
    }Position;
    
    typedef struct
    {
        int x, y;
    }Velocity;
    
    
    void function(uint8_t argCount, ...)
    {
        //alle argumente werden vom Typ `int` sein, weil durch das Concatenieren die Argumente durch die bereits definierten Zahlen ersetzt werden
    }
    
    #define foo(uint8_t argCount, ...)\
        function(argCount, CONCATENATE_EACH_ELEMENT(__VA_ARGS__));
    
    int main()
    {
        foo(2, Position, Velocity);
    }
    

    Intern soll Position mit dem Wert von PositionFooBar assoziiert werden. Dafür brauche ich ein Macro, welches für jeden Wert von den vielen, die übergeben werden können, den Postfix FooBar hinzufügt, damit diese an eine Funktion übergeben werden können. Diese Funktion nimmt aber nur int entgegen. Das wird aber gewährleistet, weil ja zu dem Argument Position der Postfix FooBar concateniert wird, womit das Argument zu PositionFooBar wird, was ja als `int``definiert ist.

    Ich glaube ich habe durch die ganzen Infos nur Verwirrung gestiftet. Ich brauche einfach ein Macro, dass jedes einzelne Element eines variadic Arguments concateniert, anstatt nur das erste.



  • Du denkst viel zu statisch, nämlich in Makros. Makros sind Scheiße, eben weil sie per Definition nur statischen (also Compilezeit)Fokus haben, ein Programm lebt aber von seiner Dynamik - immer und überall.

    Das einzig Statische an diesem Programm sind die Typen und deren Funktionsarray.
    Mit einer Funktion pro Typ kannst du viel besser dynamisch arbeiten und auf deren Eigenarten eingehen.

    #include <stdio.h>
    
    enum {POSITION,VELOCITY};
    
    typedef struct { int x, y; } Position;
    typedef struct { double x, y; } Velocity;
    
    void P(Position*p){printf("Position %d %d\n",p->x,p->y);}
    void V(Velocity*v){printf("Velocity %f %f\n",v->x,v->y);}
    
    void (*func[])(void*)={P,V};
    
    int main()
    {
        Position p={1,2};
        Velocity v={3,4};
        
        func[POSITION](&p);
        func[VELOCITY](&v);
        
        return 0;
    }
    

    https://onlinegdb.com/S1ZMDUQfI



  • @Wutz Vielen Dank für deine Antworten im Übrigen 🙂 . Ich möchte aber keine Instanzen übergeben, sondern nur den Typ registrieren. Außerdem hängt der Ort, wo die Signaturen der Typen gespeichert werden, vom ersten Parameter ab. Außerdem möchte ich sehr viele Typen auf einmal übergeben. Und das auch viele Male, weil es ja viele verschiedene Möglichkeiten für den ersten Parameter gibt.
    Wie gesagt, möchte ich verschiedene Typen intern repräsentieren, und mit einer Nummer, weil diese für andere Dinge sehr wichtig ist. Daher bräuchte ich nur eine Möglichkeit, viele Typen auf einmal zu übergeben und diesen dann eine Nummer zuzuordnen. Wenn man nur einen übergibt, kann man ## benutzen, bei vielen Argumenten nicht. Kann ich va_list auch in Macros benutzen? Das würde der Lösung etwas näher kommen



  • Schau dir mal Boost Preprocessor an und deren Funktionalität bzgl. Variadic Macros.
    Dort gibt es z.B. BOOST_PP_SEQ_FOR_EACH, s.a. Appendix A - An Introduction to Preprocessor Metaprogramming (Übersicht "A.4.5.1 Sequences" fast ganz unten).



  • Hab eine Lösung gefunden.

    #define BX_foreach(Join,What, ...) BX_foreach_(BX_argc(__VA_ARGS__), Join, What, __VA_ARGS__)
    
    #define BX_foreach_(N, Join, What, ...) BX_paste(BX_cat(BX_foreach_, N)(Join, What, __VA_ARGS__))
    #define BX_cat(X,Y)  BX_cat_(X,Y) //{{{
    #define BX_cat_(X,Y) X##Y //}}}
    #define BX_call_first(Fn,...) Fn ( __VA_ARGS__ )
    #define BX_paste(...) __VA_ARGS__
    
    #define BX_argc(...) BX_argc_(X,__VA_ARGS__) //{{{
    #define BX_argc_(...) BX_argc__(,__VA_ARGS__,8,7,6,5,4,3,2,1,0,0)
    #define BX_argc__(_,_0,_1,_2,_3,_4,_5,_6,_7,_8,Cnt,...) Cnt //}}}
    #define BX_foreach_1(Join, What,  x) BX_call_first(What,  x)
    #define BX_foreach_2(Join, What,  x,...)BX_call_first(What,x) Join BX_foreach_1(Join, What,  __VA_ARGS__)
    #define BX_foreach_3(Join, What,  x,...)BX_call_first(What,x) Join BX_foreach_2(Join, What,  __VA_ARGS__)
    #define BX_foreach_4(Join, What,  x,...)BX_call_first(What,x) Join BX_foreach_3(Join, What,  __VA_ARGS__)
    #define BX_foreach_5(Join, What,  x,...)BX_call_first(What,x) Join BX_foreach_4(Join, What,  __VA_ARGS__)
    #define BX_foreach_6(Join, What,  x,...)BX_call_first(What,x) Join BX_foreach_5(Join, What,  __VA_ARGS__)
    #define BX_foreach_7(Join, What,  x,...)BX_call_first(What,x) Join BX_foreach_6(Join, What,  __VA_ARGS__)
    

    Das kann so benutzt werden:

    #define print(x) printf("%i", x)
    
    int main()
    {
        BX_foreach(;,print, 1, 2, 3, 4)
    }
    


  • @Th69 Danke, sehr interressante Bibliothek



  • @Th69 Das Problem an dem BX_foreach ist, dass man abgesehen von den Elementen in __VA_ARGS__ keine anderen Daten an die Funktion übergeben kann. Deine lösung mit BOOST_PP_SEQ_FOR_EACH_I(macro, data, seq) scheint schon zusätzliche Daten an die Funktion übergeben zu können. Aus der Dokumentation wird mir aber nicht ganz klar, wie ich das Macro zu nutzen habe. könntest du mir vielleicht ein Beispiel zeigen, bei dem auch zusätzliche Daten an die Funktion übergeben werden können? Wie muss der Kopf der Funktion foo aussehen, wenn ich einerseits bestimmte daten und zusätzlich ein element von __VA_ARGS__ übergeben will?

    #define bar(data, ...)\
       BOOST_PP_SEQ_FOR_EACH_I(foo data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) 
    


  • Bei BOOST_PP_SEQ_FOR_EACH gibt es doch ein Beispiel.
    Bei dir also so ähnlich (für void func(int type)):

    #define MACRO(r, data, elem) func(BOOST_PP_CAT(data, elem));
    
    #define bar(data, ...)\
       BOOST_PP_SEQ_FOR_EACH(MACRO, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
    
    bar(Type_, x, y, z)
    

    Und bei BOOST_PP_SEQ_FOR_EACH_I käme noch ein weiterer Parameter (Index) bei MACRO hinzu.



  • @Th69 Vielen Dank, es funktioniert.



  • 👍


Log in to reply