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
首先展开。在前一种情况下,如果say
NO\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
不会剪切它)。不幸的是,我不知道如何在预处理器中进行这种间接处理。