Präprozessor - Zahl zu String



  • Huhu,

    Ich hab mich gerade bisschen mit dem Präprozessor gespielt, da ich ein assert implementieren wollte. Das sieht nun wie folgt aus.

    #define TO_STRING_IMPL(s) #s
    #define TO_STRING(s) TO_STRING_IMPL(s)
    
    #define ASSERT(cond) if(!(cond)) throw assertion_failure(__FILE__ "(" TO_STRING(__LINE__) "): " #cond);
    

    Aufgefallen ist mir, dass wenn ich TO_STRING_IMPL weglasse und direkt bei TO_STRING "#s" hinschreibe, dann in der Fehlermeldung einfach "__LINE__" stehen habe. Und wenn ich das TO_STRING Makro ganz weglasse, kriege ich einen Fehler beim Kompilieren. Auf der Seite von Boost.Preprocessor habe ich irgendwas davon gelesen, dass der Präprozessor das irgendwie in Ebenen abarbeitet, aber verstanden hab ich das nicht. Kann mir das jemand erklären?

    Grüße,
    PI



  • Das Problem ist, dass # und ## verhindern, dass dia Makroargumente expandiert werden. __LINE__ wird also nicht in die Zeilennummer expandiert, sondern einfach nur stringifiziert (also zum String "__LINE__"). Durch die Indirektion wird erst das Makro expandiert, und dann das Ergebnis stringifiziert.
    Grundregel: Makros (__LINE__ *ist* ein Makro) werden im Makrorumpf expandiert, es sei denn, es steht ein # oder ein ## vor dem zu expandierenden Makro im Rumpf.



  • Okay, das erklärt schonmal, warum ich die erste Indiektion brauche. Aber wozu die zweite? Wenn ich TO_STRING(__LINE__) schreibe, und TO_STRING(s) einfach als #s definiert ist, müsste nach der Expandierung doch #<zeilennummer> da stehen.



  • Ohne Indirektion entwickelt sich das so:

    TO_STRING(__LINE__)
    #__LINE__
    "__LINE__"
    

    Da nach 16.3 (7) in C++03 der #-Token die Expansion seines Parameters unterbindet.

    Mit der Indirektion entwickelt sich das so:

    TO_STRING(__LINE__)
    TO_STRING_IMPL(__LINE__)
    TO_STRING_IMPL(123)
    #123
    "123"
    


  • Danke, ich denke, ich habs nun verstanden. Gibt es eigentlich irgendwo eine brauchbare Referenz zu Boost.Preprocessor?



  • 314159265358979 schrieb:

    Gibt es eigentlich irgendwo eine brauchbare Referenz zu Boost.Preprocessor?

    Leider nein. Ich habe auch vor einer Weile mehrere Stunden in eine entsprechende Suche investiert, ohne zufriedenstellendes Ergebnis. Es gitb ein paar Beispiele im Netz, aber nichts was für Einsteiger schnell zu durchdringen wäre. Hat mir einige Kopfschmerzen bereitet, da einen Ersatz für die in MSVC2010 nicht vorhandenen variadic templates zu basteln 😕



  • Ich glaube, die Boost-Leute machen das ggf. mit Selbst-Includes, nach dem Motto

    #if COUNTER > 0
    #define NEXT_COUNTER DECREASE(COUNTER)
    #undef  COUNTER
    #define COUNTER NEXT_COUNTER
    #undef  NEXT_COUNTER
    
    #include __FILE__
    #endif
    

    ...um dann COUNTER in BOOST_PP_ENUM_FOO o.ä. zu schmeißen. Wahrscheinlich sind die auch froh, wenn variadische Templates überall unterstützt werden und sie den ganzen Kram los sind.



  • #include <boost/preprocessor.hpp>
    
    #define NUMARGS 10
    
    #define VAR_PARAMS(n, name) BOOST_PP_ENUM_PARAMS(n, typename name) BOOST_PP_COMMA_IF(n) typename = void // dummy-param
    #define VAR_VALUES(n, name_t, name_v) BOOST_PP_ENUM_BINARY_PARAMS(n, name_t, name_v)
    
    #define BOOST_PP_LOCAL_MACRO(n) \
    	template <VAR_PARAMS(n, T)> \
    	void foo(VAR_VALUES(n, T, t)) \
    	{}
    
    #define BOOST_PP_LOCAL_LIMITS (0, NUMARGS)
    
    #include BOOST_PP_LOCAL_ITERATE()
    

Anmelden zum Antworten