要将定义的(X)返回为true或false的宏

时间:2014-10-09 19:41:26

标签: c++ c macros c-preprocessor

我想要一系列宏来替换以下代码

#ifdef FOO
    return true;
#else
    return false;
#endif

类似

return MAGICLY_EXPANDING_IFDEFINED_MACRO(FOO);

正如你猜测的那样,有很多FOO,足以将4行减少到1会很酷。但实际上它会用一行替换一个怪物切换语句。

3 个答案:

答案 0 :(得分:6)

在C ++中,defined的行为仅针对条件包含(#if#elif)指定。所以你不能以任何其他方式使用它。

(相关规则见标准第16.1节)

但是,如果你想检测特别是#define到空字符串的宏,你不需要defined(),你可以这样做:

#include <iostream>

/* this matches */
#define FOO

/* this will not */
#undef BAZ

/* nor will these */
#define BAR 0
//#define BAR 1

#define STRINGIZE(x) (#x)
#define EXPAND_IF_DEFINED(y) (!*STRINGIZE(y))

int main()
{
    std::cout << +EXPAND_IF_DEFINED(FOO) << '\n'
              << +EXPAND_IF_DEFINED(BAR) << '\n'
              << +EXPAND_IF_DEFINED(BAZ) << '\n';
}

警告,-D选项不是空字符串。要处理这种情况,你可以使用像

这样的东西
#define IS_MACRO_DEFINED_OR_ONE(y) (!*STRINGIZE(y) || '1'==*STRINGIZE(y))

更强大的测试将是

#define IS_MACRO_DEFINED_NOT_TO_ITSELF(y) strcmp(#y, STRINGIZE(y))

由于文字是编译时常量,编译器可能会在编译期间将strcmp调用优化为常量truefalse。您还可以使用constexprstrcmp来使用。

答案 1 :(得分:4)

对于像#define FOO#define FOO 1这样的简单定义,下面的宏会运行良好,但更通用的解决方案是在@BenVoigt的回答中。

#define MAGICLY_EXPANDING_IFDEFINED_MACRO_I(X) (#X[0] == 0 || #X[0] == '1')
#define MAGICLY_EXPANDING_IFDEFINED_MACRO(X) MAGICLY_EXPANDING_IFDEFINED_MACRO_I(X)

DEMO


Q&amp; A部分

  

它如何运作?

奇怪的# - 某些字符串化了define的值,或者定义了名称本身(如果没有定义)。因此,对于已定义的FOO(具有空内容),编译器最终会遇到条件:

(""[0] == 0 || ""[0] == '1')

而对于未定义的FOO,条件是:

("FOO"[0] == 0 || "FOO"[0] == '1')

== 0部分匹配每个原始字符串文字\0字符(即使是空的""},而== '1'条件如果有人定义了值1,就像#define FOO 1

一样

答案 2 :(得分:2)

宏通常是一条糟糕的路线。你想达到什么目的?像这样的东西会起作用:

//Stash this away in a header file
#ifndef FOO
#define RETURN false
#else
#define RETURN true
#endif

return RETURN;