C\C++ Preprocessor different arg for overloaded macros
I want to realize logging in my project. I have macro, smth like
__LOG_TRACE(lg, expr,...) LOG_TRACE_STREAM(lg) <&开发者_JAVA百科lt; expr;
So I want to realize interface for this macro - another macro, but I want to support 2 types:
LOG_TRACE(msg);
LOG_TRACE(my_logger, msg);
I have some global logger, and first macro will write msg
using global logger.
Second macro will take my_logger
and write msg
using it.
I can make it with LOG_TRACE(msg, my_logger);
- but it's not good, it's harder to read in code. Order of arguments in __LOG_TRACE
is not necessary.
Upd: I don't mean overloading macros. Look - for example I can do this
#define LOG_TRACE(...) __LOG_TRACE(__VA_ARGS__, current_active)
Now I can write
LOG_TRACE(msg);
LOG_TRACE(msg, logger);
But I want not msg,logger
and logger,msg
Macro overloading is not allowed in C or C++. But there are workarounds. Here's an article that will help you "overload" your macro: http://cplusplus.co.il/2010/08/31/overloading-macros/
If you don't have a variable number of loggers, i recommend you to make a macro for each logger. ex (LOG_TRACE_XML, LOG_TRACE_OUT, LOG_TRACE_TXT). Because simpler is better.
But a better way to do this is to have LOG_TRACE_ERROR/ LOG_TRACE_WARNING/ LOG_TRACE_INFO and manage the way these macros behave using IPC or another macro (SET_MODE(XML/TXT/OUT))
You cannot overload pre-processor macros, your compiler will consider this a redeclaration, rather than an overload, and so only the 2nd will be valid.
You should attempt to name your macros differently, both for readability and because that's the only way you'll get the functionality you want.
Why not make it a function + do and stringify expression macro?
#define DO_AND_RETURN_STRING_EXPR(x) (x,#x)
ov(DO_AND_RETURN_STRING_EXPR(y))
ov(my_logger, DO_AND_RETURN_STRING_EXPR(y))
(note I haven't tested this code).
__VA_ARGS__
is an extension to the current C++ standard, but if you are willing to play with this P99 has a lot of utility macros to achieve what you want. In particular macros that implement conditionals according to the number of arguments they are called.
#define LOG_TRACE(...) \
P99_IF_EQ_1(P99_NARG(__VA_ARGS__)) \
(LOG_TRACE_(my_logger, __VA_ARGS__)) \
(LOG_TRACE_(__VA_ARGS__))
P99 is not really C++ compatible, so you'd have to adapt things a bit.
BTW, identifiers that start with _
and a capital letter or another underscore are reserved by C and C++. Double underscores in general are not allowed for C++ because they could interfere with name mangling. So you'd better chose a different name for your base macro.
精彩评论