Макрос подсчета аргументов с нулевыми аргументами для VisualStudio
gcc поддерживает макросы подсчета аргументов с нулевыми аргументами в соответствии с соглашением ## __VA_ARGS__
. Следующие работы скомпилированы с gcc:
#include <stdio.h>
#define NARGS(...) __NARGS(0, ## __VA_ARGS__, 5,4,3,2,1,0)
#define __NARGS(_0,_1,_2,_3,_4,_5,N,...) N
int main()
{
printf("%d\n", NARGS()); // prints 0
printf("%d\n", NARGS(1)); // prints 1
printf("%d\n", NARGS(1, 2)); // prints 2
return 0;
}
Есть ли эквивалент для VisualC++, который будет работать с макросами без аргументов? Нестандартные расширения или приемы принимаются.
РЕДАКТИРОВАТЬ: Исправлен пример для работы с расширениями GCC и компилятором C++.
Ответы
Ответ 1
Следующий пример отлично работает в VisualStudio 2010 и более новых, gcc и clang с включенными нестандартными расширениями. В компиляторах Microsoft предполагается, что конечная запятая в макросе AUGMENTER будет удалена препроцессором, когда аргумент count равен нулю. Это не стандарт, и он также был опубликован. В gcc и clang используется широко известное ## __VA_ARGS__
нестандартное расширение.
#include <stdio.h>
#ifdef _MSC_VER // Microsoft compilers
#define EXPAND(x) x
#define __NARGS(_1, _2, _3, _4, _5, VAL, ...) VAL
#define NARGS_1(...) EXPAND(__NARGS(__VA_ARGS__, 4, 3, 2, 1, 0))
#define AUGMENTER(...) unused, __VA_ARGS__
#define NARGS(...) NARGS_1(AUGMENTER(__VA_ARGS__))
#else // Others
#define NARGS(...) __NARGS(0, ## __VA_ARGS__, 5,4,3,2,1,0)
#define __NARGS(_0,_1,_2,_3,_4,_5,N,...) N
#endif
int main()
{
// NARGS
printf("%d\n", NARGS()); // Prints 0
printf("%d\n", NARGS(1)); // Prints 1
printf("%d\n", NARGS(1, 2)); // Prints 2
fflush(stdout);
#ifdef _MSC_VER
// NARGS minus 1
printf("\n");
printf("%d\n", NARGS_1(1)); // Prints 0
printf("%d\n", NARGS_1(1, 2)); // Prints 1
printf("%d\n", NARGS_1(1, 2, 3)); // Prints 2
#endif
return 0;
}
Макросы были протестированы с помощью реальных компиляторов, Wandbox и Webcompiler
Ответ 2
Вот код, который работает с gcc (5.3) И VisualStudio2010:
#include <stdio.h>
#define expand(x) x
#define prefix(...) 0,##__VA_ARGS__
#define lastof10(a,b,c,d,e,f,g,h,i,j,...) j
#define sub_nbarg(...) expand(lastof10(__VA_ARGS__,8,7,6,5,4,3,2,1,0))
#define nbarg(...) sub_nbarg(prefix(__VA_ARGS__))
#define test(...) printf("(%s) ---> %d\n",""#__VA_ARGS__,nbarg(__VA_ARGS__))
int main ()
{
test() ; // () ---> 0
test(1) ; // (1) ---> 1
test(1,2) ; // (1,2) ---> 2
test(1,2,3) ; // (1,2,3) ---> 3
test(1,2,3,4) ; // (1,2,3,4) ---> 4
test(1,2,3,4,5) ; // (1,2,3,4,5) ---> 5
test(1,2,3,4,5,6) ; // (1,2,3,4,5,6) ---> 6
return 0 ;
}
Ответ 3
Не могли бы вы попробовать:
#define __NARGS(_1, _2, _3, _4, _5, VAL, ...) VAL
#define NARGS(...) (sizeof(#__VA_ARGS__) == sizeof("") ? 0 : __NARGS(__VA_ARGS__, 5, 4, 3, 2, 1))
Это работает с g++ (Demo).
Ответ 4
Использование идеи @Jarod42 и BOOST_PP_VARIADIC_SIZE boost можно записать следующим образом.
#include <stdio.h>
#include <boost/preprocessor/variadic/size.hpp>
#define FOO(...) (sizeof(""#__VA_ARGS__) == sizeof("") ? 0 : BOOST_PP_VARIADIC_SIZE(__VA_ARGS__))
int main()
{
printf("%d\n", FOO()); // prints 0
printf("%d\n", FOO(1)); // prints 1
printf("%d\n", FOO(1, 2)); // prints 2
return 0;
}