Нужно по-настоящему использовать препроцессор по максимуму, чтобы отличать дополнительные аргументы от случая, когда они присутствуют.Но с 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 объединяются с токеном MY_ASSERT
для формирования имени макроса, к которому мы переходим к пересылке аргументов.
MY_ASSERT1
(с аргументами) - ваш исходный макрос.MY_ASSERT0
заменяет себя на MY_ASSERT1(expr,)
, запятая означает, что мы передаем другой аргумент (таким образом выполняя требование для одного дополнительного аргумента), но это пустая последовательность токенов, поэтому она ничего не делает.
Выможет увидеть его вживую .
Так как мы уже спустились по этой кроличьей норе, если кто-то не хочет втягивать 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. Теперь мы просто подключаем его к тому же месту, где мы использовали повышение раньше:
#define MyAssert(...) CONCAT(MY_ASSERT, HAS_ARGS(__VA_ARGS__))(__VA_ARGS__)
Вы можете повозиться с этим здесь