想象一下,我有一些“声明类似”功能,如果定义了特定的宏,则以一种方式声明宏,否则,则以另一种方式声明宏:
// in some header assert2.hpp
#ifdef NO_ASSERT2
#define assert2(x)
#else
#define assert2(x) assert2_handler(x);
#endif
这里,NO_ASSERT2
宏与标准assert(3)中的NDEBUG
宏非常相似。
但是,我想做的是允许用户在包含文件之前用自己的宏覆盖NO_ASSERT2
检查。例如,如果您这样包含assert2.hpp
:
#define NO_ASSERT_KEY NO_ASSERT_CUSTOM
#include "assert2.hpp"
然后将检查宏NO_ASSERT_CUSTOM
而不是此翻译单元的默认NO_ASSERT2
。
它不必完全像上面那样工作-我只需要某种方法就可以按文件覆盖行为,而不需要在包含位置超过上面显示的1行样板。 / p>
答案 0 :(得分:1)
这不是很漂亮...但是这种方法可能对您有用。假定使用#define FOO
,#define FOO 1
或-DFOO
定义了宏(假设通常会创建与#define FOO 1
等效的东西)。
#define SECOND(...) SECOND_I(__VA_ARGS__,,)
#define SECOND_I(A,B,...) B
#define GLUE3(A,B,C) GLUE3_I(A,B,C)
#define GLUE3_I(A,B,C) A##B##C
#define AGLUE3(A,B,C) AGLUE3_I(A,B,C)
#define AGLUE3_I(A,B,C) A##B##C
#define TEST_ASSERT_KEY GLUE3(NO_ASSERT_PROBE,0_,NO_ASSERT_KEY)
#define NO_ASSERT_PROBE0_NO_ASSERT_KEY AGLUE3(NO_ASSERT_PROBE,0_,NO_ASSERT2)
#define NO_ASSERT_PROBE0_ ,1
#define NO_ASSERT_PROBE0_1 ,1
#define NO_ASSERT_TEST SECOND(TEST_ASSERT_KEY,0)
这样,您的用法将是:
#if NO_ASSERT_TEST
#define assert2(x)
#else
#define assert2(x) assert2_handler(x);
#endif
这里是stacked-crooked的演示。
这在预处理器中通过间接SECOND
宏使用模式匹配。这个想法是,它扩展到它的第二个参数,但是只能间接地扩展……这允许您构造一个模式作为第一个参数。通常,第一个参数会被忽略,但是如果您要匹配某些内容,则可以将其设置为第一个参数将是一个用逗号扩展的宏的位置。从而将新的第二个参数移入其中,以替换默认参数。
从这里开始更容易向后解释。 NO_ASSERT_TEST
使用TEST_ASSERT_KEY
来构造一个默认值为0
的模式。 TEST_ASSERT_KEY
构建NO_ASSERT_PROBE0_
与NO_ASSERT_KEY
串联在一起。定义NO_ASSERT_KEY
时,这将建立NO_ASSERT_PROBE0_
并与其定义扩展。否则,它将使用与NO_ASSERT_PROBE0_
串联的NO_ASSERT2
重建测试令牌。
无论哪种方式,这都是间接粘贴,因此前一种情况下的NO_ASSERT_KEY
或后一种情况的NO_ASSERT2
会先被展开。在前一种情况下,如果说NO_ASSERT_KEY
是NO_ASSERT_CUSTOM
而未定义NO_ASSERT_CUSTOM
,则会生成NO_ASSERT_PROBE0_NO_ASSERT_CUSTOM
,它只是一个普通标识符,将被忽略,从而导致0
中的SECOND
导致NO_ASSERT_TEST
中的数据丢失。但是,如果为每个NO_ASSERT_CUSTOM
定义了#define NO_ASSERT_CUSTOM
,则会产生NO_ASSERT_PROBE0_
,并扩展为,1
,从而将1
移入{ {1}}。同样,如果在命令行上按SECOND
定义了NO_ASSERT_TEST
,则(通常)使其定义等同于NO_ASSERT_CUSTOM
,这将产生-DNO_ASSERT_CUSTOM
,并扩展为{{ 1}}。
未定义#define NO_ASSERT_CUSTOM 1
的情况类似。
如果有人想拍摄,可能有一种更漂亮的方法来构建此构造。