我想要一系列宏来替换以下代码
#ifdef FOO
return true;
#else
return false;
#endif
类似
return MAGICLY_EXPANDING_IFDEFINED_MACRO(FOO);
正如你猜测的那样,有很多FOO,足以将4行减少到1会很酷。但实际上它会用一行替换一个怪物切换语句。
答案 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
调用优化为常量true
或false
。您还可以使用constexpr
版strcmp
来使用。
答案 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)
它如何运作?
奇怪的#
- 某些字符串化了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;