我有以下宏:
#define LOG(level,text)
我想定义包含级别和文本的宏:
#define MY_LOG_MESSAGE LEVEL1,"This is my log"
所以后来我可以运行:
LOG(MY_LOG_MESSAGE);
gcc 发出预处理错误:
错误:宏“LOG”需要 2 个参数,但只有 1 个给定
有任何想法吗?
我有以下宏:
#define LOG(level,text)
我想定义包含级别和文本的宏:
#define MY_LOG_MESSAGE LEVEL1,"This is my log"
所以后来我可以运行:
LOG(MY_LOG_MESSAGE);
gcc 发出预处理错误:
错误:宏“LOG”需要 2 个参数,但只有 1 个给定
有任何想法吗?
您必须说服预处理器在MY_LOG_MESSAGE
宏尝试扩展之前对其进行扩展LOG()
。这可以通过使用一个简单的辅助宏来完成:
#define LOG1(x) LOG(x)
LOG1(MY_LOG_MESSAGE);
给定的参数LOG1()
在它的主体中被扩展,导致对 的有效调用LOG()
。
这与sth's answer非常相似,但允许使用一个或两个参数:
#define LOG_(level,text) implementation
#define LOG(...) LOG_(__VA_ARGS__)
#define MY_LOG_MESSAGE LEVEL1,"This is my log"
LOG(MY_LOG_MESSAGE);
LOG(LEVEL2, "Another log");
关键是LOG
导致参数在调用之前被扩展LOG_
,从而在两种情况下都给它两个参数。
如果您对每条日志消息都使用定义,则可以这样做:
#define LOG_MY_MESSAGE LOG(LEVEL1, "This is my log")
并在代码中简单地使用
LOG_MY_MESSAGE
#define ELOG(message) log(LEVEL_ERR,message)
#define WLOG(message) log(LEVEL_WARN,message)
这样您就可以将其用作
ELOG("This is error msg")
或者WLOG("Warning msg")
假设你有一个功能
void log(int loglevel,char* msg)
这不能以这种方式工作。对于预处理器,当它需要两个参数时,您只给LOG
MACRO 一个参数。
您可以通过做一些更简单的事情来解决它:
#define MY_LOG_MESSAGE LOG(LEVEL1, "This is my log")
并像这样使用它:
MY_LOG_MESSAGE
解释:
在这种情况下:
#define LOG(level,text)
#define MY_LOG_MESSAGE LEVEL1,"This is my log"
LOG(MY_LOG_MESSAGE);
MY_LOG_MESSAGE
预处理器在看到对 的调用时不会替换您的宏LOG
,它会将其作为参数传递(如函数)。
只有在那之后,当预处理器替换LOG
宏时,它才会重新扫描替换列表以查看是否有更多宏要处理。
从标准:
16.3.1 参数替换 [cpp.subst]
- 在确定了调用类函数宏的参数后,将进行参数替换。替换列表中的参数,除非前面有一个
#
或##
预处理标记或后面有一个##
预处理标记(见下文),在其中包含的所有宏都已展开后,将被相应的参数替换。在被替换之前,每个参数的预处理标记都被完全宏替换,就好像它们形成了预处理文件的其余部分一样;没有其他可用的预处理令牌。
这里说,作为另一个宏的参数传递的宏在确定了调用类似函数的宏的参数之后被扩展。
然后您还可以强制预处理器扩展宏:
#define LOG(level, text) whatever
#define MY_LOG_MESSAGE LEVEL1,"This is my log"
#define LOG_LVL1(args) LOG(args)
// ^^^^ ^^^^
// Pass a macro Will be expanded by the preprocessor here
// And LOG will receive the correct number of arguments
LOG_LVL1(MY_LOG_MESSAGE)
是的,像这样定义LOG:
#define LOG(text)
然后 LOG 只接收 1 个参数,您可以将它与您的消息一起使用
LOG(MY_LOG_MESSAGE);
预处理器从每个文件的开头到结尾,立即用替换标记列表替换任何宏。在您的情况下,LOG
首先被替换,之前MY_LOG_MESSAGE
被替换为 2 个参数,因此出现错误。
MY_LOG_MESSAGE
将被预处理器视为一个参数,因为它是一个预处理器指令。LEVEL1,"This is my log"
包含在您的内部MY_LOG_MESSAGE
,并在其他预处理器指令中使用时被视为单个预处理器参数。
用于调用简单的函数,如
void DoLogging(Level level, const std::string& msg)
您的宏将按照您的预期处理。所以DoLogging(MY_LOG_MESSAGE)
会起作用。它将在这里展开,因为它not
被用作另一个预处理器指令的参数,但在real
函数内部。有什么帮助是这样的:
#define MY_LOG_MESSAGE LOG(LEVEL1, "My message")
此外,如果您指出有多个 LOG()-宏,只需将其用作 MY_LOG_MESSAGE 的参数,如下所示:
#define MY_LOG_MESSAGE(logger) logger(LEVEL1, "My message")
在你的代码中调用它MY_LOG_MESSAGE(LOG)