Макрос подсчета аргументов с нулевыми аргументами для 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;
}