首先,我们知道Boost.Preprocessor可以满足我们的循环需求。然而,生成的代码必须能够独立工作。不幸的是,由于宏扩展的结果,#ifdef
不能工作,因此没有办法生成您问题中的代码。我们是否已经束手无策了?
还没有!我们可以利用您的宏要么不存在要么是字符串字面值的事实。考虑以下内容:
using StrPtr = char const *;
StrPtr probe(StrPtr(MACRO1));
我们在这里利用了我们老朋友最棘手的解析。第二行可以根据MACRO1
是否被定义来有两种解释方式。如果没有被定义,它相当于:
char const *probe(char const *MACRO1);
这是一个函数声明,其中MACRO1
是参数的名称。但是,当将MACRO1
定义为"B"
时,它相当于:
char const *probe = (char const *) "B";
...其中一个变量被初始化为指向"B"
的指针。然后,我们可以根据刚刚生成的内容类型进行开关操作,以查看是否发生了替换:
if(!std::is_function<decltype(probe)>::value)
std::cout << "MACRO1 " << probe << '\n';
我们可以在这里使用if constexpr
,但是std::cout
可以输出一个函数指针(它将其转换为bool
),因此无用的代码分支是有效的,并且编译器足够聪明以完全优化掉它。
最后,我们回到Boost.Preprocessor为我们生成所有这些内容:
#define PRINT_IF_DEFINED(z, n, data) \
{ \
StrPtr probe(StrPtr(BOOST_PP_CAT(MACRO, n))); \
if(!std::is_function<decltype(probe)>::value) \
std::cout << "MACRO" BOOST_PP_STRINGIZE(n) " " << probe << '\n'; \
}
#define PRINT_MACROS(num) \
do { \
using StrPtr = char const *; \
BOOST_PP_REPEAT(num, PRINT_IF_DEFINED, ~) \
} while(false)
... voilà!
在Coliru上实时查看
注意:该Coliru代码片段包括GCC和Clang的警告禁用器,这些警告针对我们可怜的最恼人的解析 :(
MACROn
的文件在你的控制之下,为什么不进一步增强它来解决这个问题呢? - GManNickG