在不知道宏的数量的情况下打印宏值

e27*_*314 30 c++ c-preprocessor

我的代码包含一个生成的文件(我事先不知道它的内容),只有一个约定我和我的用户就如何创建这个文件达成一致,所以我可以使用它.这个文件看起来像

#define MACRO0 "A"
#define MACRO1 "B"
#define MACRO2 "C"
...
Run Code Online (Sandbox Code Playgroud)

我想打印所有宏值.我目前的代码看起来像

#ifdef MACRO0
std::cout << "MACRO0 " << MACRO0 << std::endl;
#endif
#ifdef MACRO1
std::cout << "MACRO1 " << MACRO1 << std::endl;
#endif
#ifdef MACRO2
std::cout << "MACRO2 " << MACRO2 << std::endl;
#endif
Run Code Online (Sandbox Code Playgroud)

我的问题是,如何迭代生成的文件中的宏,所以我不需要复制我的代码

Que*_*tin 52

首先,我们知道我们可以依靠Boost.Preprocessor来满足我们的循环需求.但是,生成的代码必须单独工作.遗憾的是,#ifdef由于宏扩展无法工作,因此无法在您的问题中生成代码.我们烤了吗?

还没!我们可以利用您的宏都不存在或字符串文字这一事实.考虑以下:

using StrPtr = char const *;
StrPtr probe(StrPtr(MACRO1));
Run Code Online (Sandbox Code Playgroud)

我们正在利用我们的老朋友这里最令人烦恼的解析.第二行可以用两种方式解释,具体取决于是否MACRO1定义.没有它,它相当于:

char const *probe(char const *MACRO1);
Run Code Online (Sandbox Code Playgroud)

...这是一个函数声明,其中MACRO1是参数的名称.但是,当MACRO1定义为时"B",它变得等同于:

char const *probe = (char const *) "B";
Run Code Online (Sandbox Code Playgroud)

...这是一个初始化为指向的变量"B".然后我们可以打开我们刚刚生成的类型,看看是否发生了替换:

if(!std::is_function<decltype(probe)>::value)
    std::cout << "MACRO1 " << probe << '\n';
Run Code Online (Sandbox Code Playgroud)

我们可以使用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)
Run Code Online (Sandbox Code Playgroud)

......瞧!

在Coliru上看到它

注意:Coliru片段包含GCC和Clang的警告禁用,它警告我们可怜的朋友最烦恼的解析:(

  • 你利用最令人烦恼的解析......我觉得我应该低头吟唱我的不配. (18认同)
  • 这是传奇 (13认同)
  • _“我们正在利用我们的老朋友最令人烦恼的解析。”_这真是天才! (2认同)