Verschachtelte Makros



  • Hallo,

    um tonnenweise Boilerplate-Code zu vermeiden, lasse ich mir ihn von Makros erzeugen. Beispielsweise so:

    xyzLIB_DEFINE_BINARY_VALARRAY_TEMPLATE(PolyGamma, T, unsigned, typename T);
    

    Die Parameter des Makros sind: der Funktionsname, die beiden Argumente und der Template-Parameter. Nun möchte ich aber alle integralen Typen zulassen und nicht nur unsigned . Ok, das dürfte schnell gehen:

    xyzLIB_DEFINE_BINARY_VALARRAY_TEMPLATE(PolyGamma, T, U, typename T, typename U);
    

    Uups, doch nicht! Der neue Template-Parameter wird als Makro-Parameter interpretiert. Klammern gehen auch nicht da Template-Parameterliste. Ok, dann hab ich einen Hack gefunden:

    #define xyzLIB_ID_2(x, y) x, y
    xyzLIB_DEFINE_BINARY_VALARRAY_TEMPLATE(PolyGamma, T, U, xyzLIB_ID_2(typename T, typename U));
    

    Und hier meldet sich meine Unwissenheit, ob der Code denn standardkonform ist oder nicht. Bearbeitet der Präprozessor den Code solange bis er keine Symbole mehr findet? Und ist garantiert, dass das äussere Makro vor dem inneren ersetzt wird? Ich hätte es eigentich mit Variadic Macros und __VA_ARGS__ machen können, will meine Bibliothek noch kompatibel zu C++03 halten.

    Danke im Voraus und Gruss.


  • Mod

    Das neue Template-Argument wird als Makro-Parameter interpretiert.

    Argument? Wenn du U meinst - das ist der Template-Parameter. Und warum kannst du nicht einfach den Namen zu V ändern?

    Ich bin ein wenig verwirrt. Kannst du ein klitzekleines Testprogramm posten?



  • Oh, natürlich der Template-Parameter, nicht das Argument (also typename U ). Hab's im OP angepasst.

    Edit:
    Hier der Code (der auskommentierte Teil ist der, der nicht geht):

    #define GEN(Fun, Ret, Arg1, Arg2, TemplateArgs)	\
    template<TemplateArgs>	                        \
    Ret Fun(Arg1, Arg2)		                        \
    {						                        \
    	return Ret();                               \
    }
    
    GEN(f, int, T, T, typename T);
    // GEN(g, int, T, U, typename T, typename U);
    
    int main()
    {
    	f(5, 7);
    	// g(5, 7.);
    }
    

    http://ideone.com/KZmUSx

    Und hier mein fragwürdiger Hack:

    #define GEN(Fun, Ret, Arg1, Arg2, TemplateArgs)	\
    template<TemplateArgs>	                        \
    Ret Fun(Arg1, Arg2)		                        \
    {						                        \
    	return Ret();                               \
    }
    
    #define Id2(x, y) x, y
    
    GEN(f, int, T, T, typename T);
    GEN(g, int, T, U, Id2(typename T, typename U));
    
    int main()
    {
    	f(5, 7);
    	g(5, 7.);
    }
    

    http://ideone.com/KXLPym


  • Mod

    😃
    Ja, das ist absolut in Ordnung und standardkonform.

    Und ist garantiert, dass das äussere Makro vor dem inneren ersetzt wird?

    Nein, andersherum:

    [cpp.subst]/1 schrieb:

    A parameter in the replacement list […] is replaced by the corresponding argument after all macros contained therein have been expanded.

    Es wird also Id2(typename T, typename U) expandiert. Das ergibt die pp-tokens typename T, typename U . Und dann wird in der replacement list von GEN TemplateArgs durch diese pp-tokens ersetzt.



  • Ah, ich verstehe. Gut, danke. 🙂


Anmelden zum Antworten