简体   繁体   中英

scoped anonymous variable declaration within a macro

I have a macro which I use to log, and within the macro I'd like to define a temprecord as follows:

#define MACRO_LOG(...)             \
temprecord t;                      \
logger->logmessage(__VA_ARGS___); 

with temprecord() { logger->increaseIndent() } and in the destructor a decreaseIndent() .

The association with a name (eg, variable) gives an object scope which controls its lifetime. By not naming an object, it's lifetime is bound

source Why do un-named C++ objects destruct before the scope block ends?

Because the temprecord has lifetime of the scope, if I have

{
   MACRO_LOG("stackoverflow example");
   MACRO_LOG("stackoverflow example");
}

Outside the scope I will have 0 indent and in the scope 1 and 2 indents. However , as I name my temprecord t I get a redefinition of variable names.. and if I do not declare it I do not get the scope that I want.

How to go about this? I thought of using a container to put the temprecords in, but can't seem to solve the puzzle..

What I wish to accomplish is double indentation in my mentioned scope, and not single indentation within the MACRO_LOG scope.

Macro replacement is just an in-place text replacement. So, given the #define you have shown, the code:

{
   MACRO_LOG("stackoverflow example");
   MACRO_LOG("stackoverflow example");
}

Expands to this:

{
    temprecord t;
    logger->logmessage("stackoverflow example");;
    temprecord t;
    logger->logmessage("stackoverflow example");;
}

Which should make it obvious why the macro doesn't work when used multiple times in the same scope, since t is declared multiple times.

There are some different ways you can solve this:

1) wrap the content of MACRO_LOG() in curly braces so that temprecord t is in its own scope, eg:

#define MACRO_LOG(...) { \
    temprecord t;                      \
    logger->logmessage(__VA_ARGS___);  \
}

Which would expand the code to this:

{
    {
        temprecord t;
        logger->logmessage("stackoverflow example");
    };
    {
        temprecord t;
        logger->logmessage("stackoverflow example");
    };
}

2) append __LINE__ to t to give each copy of the temprecord a more unique name, eg:

(See Creating C macro with ## and __LINE__ (token concatenation with positioning macro) )

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)

#define MACRO_LOG(...) \
temprecord TOKENPASTE2(t_, __LINE__); \
logger->logmessage(__VA_ARGS___);

Which would expand the code to this:

{
    temprecord t_12345;
    logger->logmessage("stackoverflow example");;
    temprecord t_12347;
    logger->logmessage("stackoverflow example");;
}

3) use the comma operator to define a nameless variable in the same expression that calls logmessage() , the variable will not go out of scope until logmessage() returns, eg:

#define MACRO_LOG(...) temprecord(), logger->logmessage(__VA_ARGS___);

Which would expand the code to this:

{
    temprecord(), logger->logmessage("stackoverflow example");;
    temprecord(), logger->logmessage("stackoverflow example");;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM