Makros: abschliessendes ; erzwingen



  • Hallo Leute!

    ich ueberlege gerade, wie man bei einem Makro, ein abschliessendes ; erzwingen kann.

    beispiel:

    RequireInRange(i,0,size()-1);

    dies expandiert zu

    if( !(0 <= i && i <= size()-1) ) throw OutOfRange(__FILE__,STRINGIZE(__LINE__));
    

    soweit so gut.
    das ; ist hier ja zwingen, da throw nunmal abgeschlossen werden muss.

    doch zu was expandiert es wenn Require deaktiviert ist?

    bzw. was ist, wenn Require zu einem mehrzeiligen code expandiert??

    das klassische
    do{ foo(); while(false)
    will ich nicht verwenden, da es leider einen haufen compiler gibt, die die funktion dann nicht mehr inlinen koennen 😞

    wie macht ihr das?

    die loesung aus den C++ FAQ Lite gefaellt mir nicht:

    #define RequireInRange(var,min,max) if(1) { \
      if( !(min <= var && var <= max) ) throw OutOfRange(__FILE__,STRINGIZE(__LINE__)); } else
    

    denn wenn man
    RequireInRange(i,0,10)
    cout<<"Hallo";
    schreibt, dann wundert man sich vielleicht warum "Hallo" nie ausgegeben wird...
    denn es kommt kein syntax fehler 😞



  • doch zu was expandiert es wenn Require deaktiviert ist?

    Ich kenne mich mit diesen Makro-Tricks nicht so aus, aber geht nicht z.B. eine forward-Deklaration. Z.B. von OutOfRange?



  • hmm, mach doch ein

    #define A(b) { int a=b; } 1+1
    

    das 1+1 sollte der Compiler ja einfach weglassen (musst nur aufpassen, weil der vielleicht eine Warnung oder so ausspuckt)



  • HumeSikkins schrieb:

    Ich kenne mich mit diesen Makro-Tricks nicht so aus, aber geht nicht z.B. eine forward-Deklaration. Z.B. von OutOfRange?

    ich weiss zwar nicht, ob du das gemeint hast, aber es hat mich auf eine idee grebracht:

    namespace debug
    {
    template<typename A, typename B, typename C>
    inline void RequireInRange(A var, B min, C max, char const* file, char const* line)
    {
      if(! (min <= var && var <= max) ) throw OutOfRange(file,line);
    }
    
    inline void NoOp() {}
    }
    #ifndef NDEBUG
    #  define RequireInRange(var,min,max) ::debug::RequireInRange((var),(min),(max),__FILE__,STRGIZE(__LINE__))
    #else
    #  define RequireInRange(var,min,max) ::debug::NoOp()
    #endif
    

    so sollte es doch gehen, oder?
    auf A, B und C kommen noch CallTraits drauf um garantiert jede teure kopie zu verhindern - und NoOp() sollte auch zu einem nichts werden, oder?

    oder habe ich jetzt etwas uebersehen?



  • Wie wär's, wenn du noch (void)0 dranhängst?

    #ifdef _DEBUG
    #define RequireInRange(var,min,max) if(1) { \
      if( !(min <= var && var <= max) ) throw OutOfRange(); } else ((void)0)
    #else
    #define RequireInRange(var,min,max) ((void)0)
    #endif
    

Anmelden zum Antworten