人们需要真正最大限度地使用预处理器,以便将没有附加参数的情况与存在附加参数的情况区分开来。但使用 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
必须接受至少一个参数(标准)。然后我们对参数进行计数,减一,然后转换为布尔值(0 或 1)。这个 0 或 1 连接到 tokenMY_ASSERT
形成一个宏名称,我们继续将参数转发到该宏名称。
MY_ASSERT1
(带参数),是你原来的宏。MY_ASSERT0
将自身替换为MY_ASSERT1(expr,)
,尾随逗号意味着我们传递另一个参数(从而满足一个额外参数的要求),但它是一个空标记序列,因此它什么也不做。
You can 现场观看.
由于我们已经陷入了这个兔子洞,如果不想引入 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__)
你可以在这里修改它