问题描述
我正在尝试使用用于定义我的记录器的定义宏创建一个逻辑系统,当定义某些切换时,该宏将扩展为空。问题是,当我将多个这些开关中的一个嵌套在另一个嵌套中时(例如调用类似IF_SWITCH_1函数的宏),我得到了代码块中列出的多个错误。 是什么原因导致这些错误?我该如何解决?
//Creation of the switches
#define _ADD_PARTS2(part1,part2,...) part1 ## part2 (__VA_ARGS__)
#define _ADD_PARTS(part1,...) _ADD_PARTS2(part1,__VA_ARGS__)
#define _LOGIC_SWITCH_(name,cond,...) _ADD_PARTS(name,__VA_ARGS__)
//Toggles
#define CONDITION_1 true
#define CONDITION_2 true
//Switches
#define IF_SWITCH_2_true(a,b,c) std::cout << "Passed" << std::endl
#define IF_SWITCH_2_false(...)
#define IF_SWITCH_2(a,c) _LOGIC_SWITCH_(IF_SWITCH_2_,CONDITION_1,a,c)
#define IF_SWITCH_1_true(a,c) IF_SWITCH_2(a,c)
#define IF_SWITCH_1_false(...)
#define IF_SWITCH_1(a,c) _LOGIC_SWITCH_(IF_SWITCH_1_,c)
//Use
IF_SWITCH_2(1,1,1); //Compiles and passes
IF_SWITCH_1(1,1); //"IF_SWITCH_2" was not declared in this scope;
//_LOGIC_SWITCH_ was not declared in this scope;
//Use of undeclared indentifier IF_SWITCH_2_
//Switching on and off
#undef CONDITION_2
#define CONDITION_2 false //Any invocation from this point on wont pass past the logic switch
IF_SWITCH_2(1,1); //Wont pass
据我所知,更改定义的顺序对错误没有影响。
使用MinGW 8.10 64位编译
解决方法
是什么原因导致这些错误?
扩展只运行一次。宏一旦展开,就不会再进行嵌套嵌套调用中的再次扩展。无论如何,链条是:
IF_SWITCH_1(1,1,1)
_LOGIC_SWITCH_(IF_SWITCH_1_,CONDITION_1,1) // step 2
_ADD_PARTS(IF_SWITCH_1_,true,1)
_ADD_PARTS2(IF_SWITCH_1_,1)
IF_SWITCH_1_true(1,1)
IF_SWITCH_2(1,1)
_LOGIC_SWITCH_(IF_SWITCH_2_,1)
// _LOGIC_SWITCH_ was expanded at step #2
_LOGIC_SWITCH_(IF_SWITCH_2_,1)
// expanding stops here
我该如何解决?
首先保留带下划线前跟大写字母的标识符以供实现。请勿在自己的代码中使用此类标识符。
如果您希望进行运行时评估,我建议:
static inline void if_switch_2_execute(int a,int b,int c) {
std::cout << "passed" << std::endl;
}
#define IF_SWITCH_2(a,b,c) (CONDITION_2?if_switch_2_execute(a,c):(void)0)
#define IF_SWITCH_1(a,c) (CONDITION_1?IF_SWITCH_2(a,c):(void)0)
无论如何,解决方法是将_LOGIC_SWITCH_
的求值从_LOGIC_SWITCH_
内的嵌套调用移到上一级,这样_LOGIC_SWITCH_
仅在一个求值链中扩展一次(我愿意不知道如何解释它,这就是我的理解...:/)。这就是为什么通常#define MACRO(something) CHOOSE_FUNCTION_TO_CALL(__VA_ARGS__)(__VA_ARGS__)
来做。
#define CONDITION_1 true
#define CONDITION_2 true
#define CONCAT(a,b) a##b
#define XCONCAT(a,b) CONCAT(a,b) // this is your _LOGIC_SWITCH_
#define IF_SWITCH_2_true(a,c) std::cout << "Passed" << std::endl
#define IF_SWITCH_2_false(...)
#define IF_SWITCH_2(a,c) XCONCAT(IF_SWITCH_2_,CONDITION_2)(a,c)
#define IF_SWITCH_1_true(a,c) IF_SWITCH_2(a,c)
#define IF_SWITCH_1_false(...)
#define IF_SWITCH_1(a,c) XCONCAT(IF_SWITCH_1_,CONDITION_1)(a,c)