Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this variadic argument count macro fail with VC++?

I got the following implementation to get the number of arguments in a variadic macro (currently limited to 16 args). However, for VS2010 the output is always 1, no matter how many arguments are passed. With GCC, the output is correct, bringing me to the conclusion that I must have missed something specific for MSVC (10).

#define PP_NARGS(...) \
    _xPP_NARGS_IMPL(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)

#define _xPP_NARGS_IMPL(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,N,...) N

int main(){
    int i = PP_NARGS(A,V,C,X,Y,Z);

    std::cout << i;

    std::cin.get();
    return 0;
}

So, question is as the title states, any help would be appreciated.

like image 888
Xeo Avatar asked Apr 03 '11 15:04

Xeo


2 Answers

Does the following work-around help?

#define EXPAND(x) x
#define PP_NARGS(...) \
    EXPAND(_xPP_NARGS_IMPL(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))

I think your macro isn't wrong in particular, but MSVC's __VA_ARGS__ expansion seems to behave differently from C99.

like image 187
Ise Wisteria Avatar answered Nov 17 '22 16:11

Ise Wisteria


The problem seems that Visual Studio is expanding __VA_ARGS__ after passing it into the subsequent macro, while gcc expands it before passing.

In your case, PP_NARGS(A,V,C,X,Y,Z) binds A,V,C,X,Y,Z to __VA_ARGS__, and then passes it as a whole to _xPP_NARGS_IMPL.

As a test, run:

#define PP_NARGS(...) \
    _xPP_NARGS_IMPL(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)

#define _xPP_NARGS_IMPL(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,N,...) \
  (std::cout << #x1 << std::endl, N) 

int main() {
  int i = PP_NARGS(A, V, C, X, Y, Z);
  std::cout << i;
  return 0;
}

You will see A, V, C, X, Y, Z printed on the screen, and not just A as you would probably expect.


A possible solution, as suggested by Ise Wisteria already, is to force the expansion via:

#define EXPAND(x) x
#define PP_NARGS(...) \
    EXPAND(_xPP_NARGS_IMPL(__VA_ARGS__,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))
like image 1
CygnusX1 Avatar answered Nov 17 '22 17:11

CygnusX1