C++ 允许在#ifdef检查中使用自定义宏
假设我有一些“类似断言”的功能,如果定义了特定宏,则以一种方式声明宏,如果未定义,则以另一种方式声明宏:C++ 允许在#ifdef检查中使用自定义宏,c++,c-preprocessor,C++,C Preprocessor,假设我有一些“类似断言”的功能,如果定义了特定宏,则以一种方式声明宏,如果未定义,则以另一种方式声明宏: // in some header assert2.hpp #ifdef NO_ASSERT2 #define assert2(x) #else #define assert2(x) assert2_handler(x); #endif 这里,NO_ASSERT2宏与标准中的NDEBUG宏非常相似 但是,我想做的是允许用户在包含文件之前,用自己的宏覆盖NO\u ASSERT2检查。例如,
// in some header assert2.hpp
#ifdef NO_ASSERT2
#define assert2(x)
#else
#define assert2(x) assert2_handler(x);
#endif
这里,NO_ASSERT2
宏与标准中的NDEBUG
宏非常相似
但是,我想做的是允许用户在包含文件之前,用自己的宏覆盖NO\u ASSERT2
检查。例如,如果您包括assert2.hpp
如下:
#define NO_ASSERT_KEY NO_ASSERT_CUSTOM
#include "assert2.hpp"
然后将检查宏NO\u ASSERT\u CUSTOM
,而不是此翻译单元的默认NO\u ASSERT2
它不必像上面那样工作-我只需要一些方法来覆盖每个文件的行为,而不需要超过上面显示在include位置的1行样板文件。这不太好。。。但这种方法可能适合你。它假设宏是使用
#define FOO
、#define FOO 1
或-DFOO
定义的(通常假设这会创建与#define FOO 1
等效的内容)
使用此选项,您的用法将是:
#if NO_ASSERT_TEST
#define assert2(x)
#else
#define assert2(x) assert2_handler(x);
#endif
这里有一个演示
这通过间接SECOND
宏在预处理器中使用模式匹配。这个想法是,它扩展到第二个论点,但只是间接地。。。这允许您将模式构造为第一个参数。通常会忽略第一个参数,但如果要匹配某个参数,可以将其设置为第一个参数是用逗号展开的宏;这将移入新的第二个参数,替换默认参数
从这里可以更容易地向后解释NO\u ASSERT\u TEST
使用TEST\u ASSERT\u KEY
构造一个默认值为0
的模式<代码>测试断言密钥生成与无断言密钥
连接的无断言密钥
。当定义了NO\u ASSERT\u KEY
时,这将构建NO\u ASSERT\u PROBE0\u
并将其定义为的扩展连接起来。否则,它将使用与NO\u ASSERT2
连接的NO\u ASSERT\u PROBE0
重建测试令牌
无论哪种方式,这都是一种间接粘贴,因此前一种情况下的NO\u ASSERT\u KEY
,或后一种情况下的NO\u ASSERT2
首先展开。在前一种情况下,如果sayNO\u ASSERT\u KEY
为NO\u ASSERT\u CUSTOM
且未定义NO\u ASSERT\u CUSTOM
,则会生成NO\u ASSERT\u PROBE0\u NO\u ASSERT\u CUSTOM
,这只是一个普通标识符,将被忽略,由于NO\u ASSERT\u测试中的SECOND
导致0
。但是如果根据定义了NO\u ASSERT\u CUSTOM
,这将产生NO\u ASSERT\u PROBE0\u
,它扩展到,1
,将1
移到第二个调用NO\u ASSERT\u TEST
。同样,如果根据命令行上的-DNO\u ASSERT\u CUSTOM
定义了NO\u ASSERT\u CUSTOM
,则(通常)会使其定义等效于#define NO\u ASSERT\u CUSTOM 1
,这将产生NO\u ASSERT\u PROBE0\u 1
,扩展到,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)
未定义NO\u ASSERT\u KEY
时的情况类似
如果有人想试一试的话,可能有一种更漂亮的方法来构建这个结构。在第二种情况下,如果定义了NO\u ASSERT\u KEY
,那么您希望发生什么呢?@CoffeeTableEspresso在这种情况下,如果定义了NO\u ASSERT\u CUSTOM
(例如,通过编译命令行上的-DNO\u ASSERT\u CUSTOM
),然后assert2
定义将是伪定义,就像原始示例中没有定义NO_assert2
一样。也就是说,NO\u ASSERT\u CUSTOM
取代了NO\u ASSERT2
。当定义了NO\u ASSERT\u KEY
时,我们将始终检查NO\u ASSERT\u CUSTOM
,或者我们检查NO\u ASSERT\u KEY
定义为?@CoffeeTableEspresso-后一种:当定义了NO\u ASSERT\u KEY
时,检查名称为NO\u ASSERT\u KEY
值的宏。或者其他一些机制:它不必像那样工作(但必须有不止一个自定义密钥,即只检查NO\u ASSERT\u custom
不会剪切它)。不幸的是,我不知道如何在预处理器中进行这种间接处理。