2011-06-25 20 views
36

lo visto en this site, el código muestra invocaciones macro utilizando una tilde en paréntesis:¿Qué significa la tilde (~) en macros?

HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (~)) 
//           ^^^ 

¿Qué quiere decir/hacer? Sospecho que solo es un argumento vacío, pero no estoy seguro. ¿Es tal vez específico de C (99) como el __VA_ARGS__ es específico de C99 y existe en C++?

+1

es un argumento ficticio – Anycorn

+1

~ es el complemento bit a bit, como probablemente sabrá. Parece solo un marcador de posición para mí. No creo que tenga ningún significado especial. –

Respuesta

28

En la página de introducción de Boost.Preprocessor, se da un ejemplo en A.4.1.1 Horizontal Repetición

#define TINY_print(z, n, data) data 

#define TINY_size(z, n, unused)         \ 
    template <BOOST_PP_ENUM_PARAMS(n, class T)>     \ 
    struct tiny_size<            \ 
     BOOST_PP_ENUM_PARAMS(n,T)         \ 
     BOOST_PP_COMMA_IF(n)          \ 
     BOOST_PP_ENUM(           \ 
      BOOST_PP_SUB(TINY_MAX_SIZE,n), TINY_print, none)  \ 
    >                \ 
    : mpl::int_<n> {}; 

BOOST_PP_REPEAT(TINY_MAX_SIZE, TINY_size, ~) // Oh! a tilde! 

#undef TINY_size 
#undef TINY_print 

se proporciona una explicación a continuación:

El proceso de generación de código se inició llamando BOOST_PP_REPEAT, un de orden superior macro que llama repetidamente la macro llamada por su segundo argumento (TINY_size). El primer argumento especifica el número de invocaciones repetidas, y el tercero puede ser cualquier dato; se pasa inalterado a la macro que se invoca. En este caso, TINY_size no utiliza esos datos, así que la elección para pasar ~ fue arbitraria. [5]

(el énfasis es mío)

Y no es la nota:

[5]~ no es una elección totalmente arbitraria. Tanto @ y $ podría haber sido una buena elección, salvo que técnicamente no son parte del conjunto de caracteres básico que se requiere implementaciones de C++ para apoyar. Un identificador como ignorado puede estar sujeto a la expansión de macro, lo que lleva a resultados inesperados.

La tilde, por lo tanto, es simplemente un marcador de posición ya que se requiere un argumento, pero ninguno es necesario. Dado que cualquier identificador definido por el usuario wannabe podría expandirse, necesita usar algo más.

Resulta que ~ es más o menos sin usar (negación binario no es que a menudo se llama) en comparación con + o - por ejemplo, por lo que hay pocas posibilidades de confusión.Una vez que se haya decidido por esto, usarlo consistentemente le da un nuevo que significa "tilde"; como usar operator<< y operator>> para transmitir datos se ha convertido en un modismo C++.

+0

Gracias, es un buen hallazgo y exactamente lo que necesitaba. :) – Xeo

+0

Mi +1, ¡Es un muy buen descubrimiento! No pude encontrar ninguna referencia estándar para él y estaba luchando por entenderlo a fondo. Tu respuesta lo ordena muy bien. –

+0

¿Cómo podría exactamente la expansión de macro generar resultados inesperados, teniendo en cuenta que el argumento (y por lo tanto, el argumento macro expandido) no aparece en la expansión de TINY_size? – Random832

3

Los argumentos a ensayar se coloca entre la macro y su paréntesis, la macro sólo se dispara si los argumentos están vacías:

_TRIGGER_PARENTHESIS_ __VA_ARGS__ (~) 

NOTA: En realidad el enlace informados afirma ella. Comprobaré si hay una referencia a esto en el estándar.

+0

En su nota: Sí, después de volver a leerla varias veces después de publicar la pregunta, me vino a la mente ... Esta no es la primera vez que hago una pregunta y algunos minutos más tarde me viene a la mente la solución ... :(Además, su primera oración de alguna manera no parece relacionarse directamente con la pregunta. – Xeo

+0

@Xeo: Lo siento, me temo que no entendí el contexto lo suficiente como para publicar una respuesta elaborada, había cabos sueltos sobre por qué solo ' ~ 'y seguí arrasando con el estándar por mucho tiempo sin éxito. Genial, ¡pero gracias a @Matthieu M., puedo dormir tranquilamente! –

+0

Gracias por tu effor de todos modos :) – Xeo

4

El ~ no hace nada. Casi cualquier otro contenido dentro de esos paréntesis funcionaría de la misma manera.

El eje de este truco es probar si _TRIGGER_PARENTHESIS_ está al lado de (~) en la expansión de _TRIGGER_PARENTHESIS_ __VA_ARGS__ (~). De cualquier manera, HAS_COMMA(...) amplía sus argumentos a cualquiera 0 o 1.

+0

Me pregunto cómo podría funcionar esto con un argumento que es una macro en sí misma .. '_TRIGGER_PARENTHESIS_ MYMACRO (~)'. – Xeo

+0

¿por qué usó '(~)' y no '(+)' o algo más? –

+0

@Johannes: hay un razonamiento proporcionado en la página Boost.Preprocessor Introduction, que he citado a continuación. El objetivo es usar un token de preprocesador válido pero raro. –