2011-04-03 16 views
16

Obtuve la siguiente implementación para obtener el número de argumentos en una macro variable (actualmente limitada a 16 args). Sin embargo, para VS2010, la salida siempre es 1, independientemente de cuántos argumentos se pasen. With GCC, la salida es correcta, lo que me lleva a la conclusión de que debo haber olvidado algo específico para MSVC (10).¿Por qué falla esta macro de recuento de argumentos variados con VC++?

#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; 
} 

Entonces, la pregunta es como dice el título, cualquier ayuda sería apreciada.

Respuesta

23

¿Ayuda la siguiente solución?

#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)) 

creo que la macro no está mal, en particular, pero la expansión de MSVC __VA_ARGS__ parece un comportamiento diferente del C99.

+0

¡Omg, * does * work! ¡Increíble! ¿Tienes una explicación de por qué? – Xeo

+1

Me alegro de poder ayudar :-) Honestamente, no puedo explicar por qué (Doh). Como escribí en la respuesta, creo que su macro está bien en el estándar C99. Interpreto el material 'EXPAND' como una solución pura y alternativa, y probablemente allí no contenga ninguna cuestión técnica interesante ... De acuerdo con [aquí] (http://connect.microsoft.com/VisualStudio/feedback/details/380090/variadic-macro-replacement), esto parece ser el comportamiento de error de VC. –

+0

Muchas gracias por esta solución. Funciona como se describe en VS14 CTP3 (donde un error, reconocido por MS en 2008 [ver el enlace de Ise], todavía está presente). –

-9

__VA_ARGS__ es una característica de idioma C99.
VC++ no es un compilador C99.
Haz los cálculos.

Es como tratar de compilar Pascal con un compilador Scheme y resulta extraño que no funcione para los pares 'begin/end'.

No tengo idea de cómo se comportan C++ y Visual Studio en todo esto.

+0

Aunque [MSDN] (http://msdn.microsoft.com/en-us/ library/ms177415% 28v = VS.100% 29.aspx) parece estar en desacuerdo con usted y por su redacción creo que debería poder usar '__VA_ARGS__'. – Xeo

+0

El ejemplo en la página que enlaza parece ser C++ (o el aún más extraño "C/C++"). Quise decir mi respuesta para reflejar solo C. – pmg

+0

Creo que [esta página msdn] (http://msdn.microsoft.com/en-us/library/teas0593.aspx) es la referencia para las macros C en Visual Studio. – pmg

1

El problema parece ser que Visual Studio se está expandiendo __VA_ARGS__después de pasándolo a la macro siguiente, mientras que gcc lo expande antes de pasar.

En su caso, se une PP_NARGS(A,V,C,X,Y,Z)A,V,C,X,Y,Z a __VA_ARGS__, y luego pasa como un todo a _xPP_NARGS_IMPL.

A modo de prueba, ejecute:

#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; 
} 

Verá A, V, C, X, Y, Z impreso en la pantalla, y no sólo A como era de esperar probablemente.


Una solución posible, según lo sugerido por Ise ya Wisteria, es forzar la expansión a través de:

#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)) 
Cuestiones relacionadas