使用可选格式化消息实现符合标准的断言宏的方法是什么?
我在 clang 中的工作,但(正确地)触发 -Wgnu-zero-variadic-macro-arguments
警告如果它被打开(例如通过 -Wpedantic
) 当在没有可选消息的情况下使用宏时。 Wandbox
#define MyAssert(expression, ...) \
do { \
if(!(expression)) \
{ \
printf("Assertion error: " #expression " | " __VA_ARGS__); \
abort(); \
} \
} while(0)
最佳答案
一个人需要真正最大限度地使用预处理器,以便区分没有额外参数和它们存在的情况。但是使用 Boost.PP 可以做到这一点:
#include <boost/preprocessor/variadic/size.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/logical/bool.hpp>
#include <boost/preprocessor/cat.hpp>
#define MyAssert(...) BOOST_PP_CAT(MY_ASSERT,BOOST_PP_BOOL(BOOST_PP_SUB(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__), 1)))(__VA_ARGS__)
#define MY_ASSERT0(expr) MY_ASSERT1(expr,)
#define MY_ASSERT1(expression, ...) \
do { \
if(!(expression)) \
{ \
std::printf("Assertion error: " #expression " | " __VA_ARGS__); \
std::abort(); \
} \
} while(0)
MyAssert
必须接受至少一个参数(标准)。然后我们计算参数,减去一个,然后转为 bool 值(0 或 1)。这个 0 或 1 连接到 token MY_ASSERT
以形成一个宏名称,我们继续将参数转发给它。
MY_ASSERT1
(带参数)是您的原始宏。 MY_ASSERT0
将自身替换为 MY_ASSERT1(expr,)
,尾随的逗号表示我们传递了另一个参数(因此满足了对一个额外参数的要求),但它是一个空标记顺序,所以它什么都不做。
您可以 see it live .
因为我们已经进入了这个兔子洞,如果不想引入 Boost.PP,可以使用通常的参数计数技巧来完成上述操作,稍作修改。首先,我们必须决定我们允许的参数的最大限制。我选择了20个,你可以选择更多。我们需要典型的 CONCAT
宏,这里是这个宏:
#define HAS_ARGS(...) HAS_ARGS_(__VA_ARGS__,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,)
#define HAS_ARGS_(a1,a2,a3,a4,a5,b1,b2,b3,b4,b5,c1,c2,c3,c4,c5,d1,d2,d3,d4,d5,e, N, ...) N
这是计算参数,但有一个转折点。当 __VA_ARGS__
是单个参数(没有额外的参数)时,N
解析为 0。否则,它被解析为 1。最多可以有 20 个额外参数表达式,其中任何数量都将解析为相同的 1。现在我们只需将它插入我们之前使用 boost 的相同位置:
#define MyAssert(...) CONCAT(MY_ASSERT, HAS_ARGS(__VA_ARGS__))(__VA_ARGS__)
关于c++ - 如何使用可选的格式化消息实现符合标准的断言宏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53986620/