Digamos que tenemos una macro como esta
#define FOO(type,name) type name
Que podríamos usar como
FOO(int, int_var);
Pero no siempre tan simple como eso:
FOO(std::map<int, int>, map_var); // error: macro "FOO" passed 3 arguments, but takes just 2
Por supuesto que podríamos hacer:
typedef std::map<int, int> map_int_int_t;
FOO(map_int_int_t, map_var); // OK
que no es muy ergonómico. Deben tratarse las incompatibilidades de tipo plus. ¿Alguna idea de cómo resolver esto con macro?
c++
c
macros
c-preprocessor
Popular
fuente
fuente
Respuestas:
Debido corchetes angulares también pueden representar (o producirse en) los operadores de comparación
<
,>
,<=
y>=
, la expansión macro no puede ignorar comas dentro de corchetes angulares como lo hace dentro de paréntesis. (Esto también es un problema para los corchetes y llaves, aunque estos suelen aparecer como pares equilibrados). Puede encerrar el argumento macro entre paréntesis:El problema es entonces que el parámetro permanece entre paréntesis dentro de la expansión de la macro, lo que evita que se lea como un tipo en la mayoría de los contextos.
Un buen truco para solucionar esto es que en C ++, puede extraer un nombre de tipo de un nombre de tipo entre paréntesis utilizando un tipo de función:
Debido a que la formación de tipos de función ignora los paréntesis adicionales, puede usar esta macro con o sin paréntesis donde el nombre del tipo no incluye una coma:
En C, por supuesto, esto no es necesario porque los nombres de tipo no pueden contener comas fuera de paréntesis. Entonces, para una macro en varios idiomas, puede escribir:
fuente
template<class KeyType, class ValueType> void SomeFunc(FOO(std::map<KeyType, ValueType>) element) {}
si aplico esta solución aquí, las estructuras detrás de la macro se convierten en tipos dependientes y ahora se requiere el prefijo del nombre de tipo en el tipo. Puede agregarlo, pero la deducción de tipo se ha roto, por lo que ahora debe enumerar manualmente los argumentos de tipo para llamar a la función. Terminé usando el método de temple de definir una macro para la coma. Puede que no se vea tan bonito, pero funcionó perfectamente.[]
y{}
, no lo son, solo funciona con()
tristeza. Ver: Sin embargo, no hay ningún requisito de corchetes o llaves para equilibrar ...#define PROTECT(...) argument_type<void(__VA_ARGS__)>::type
. Ahora es posible pasar argumentos fácilmente incluso a través de múltiples macros y para tipos simples puede omitir PROTECT. Sin embargo, los tipos de función se convierten en punteros de función cuando se evalúan de esta maneraSi no puede usar paréntesis y no le gusta la solución SINGLE_ARG de Mike, simplemente defina una COMMA:
Esto también ayuda si desea encadenar algunos de los argumentos macro, como en
que imprime
std::map<int , int> has typeid name "St3mapIiiSt4lessIiESaISt4pairIKiiEEE"
.fuente
#define STRVX(...) STRV(__VA_ARGS__)
y#define STRV(...) # __VA_ARGS__
, entoncesstd::cout << STRV(type<A COMMA B>) << std::endl;
se imprimirátype<A COMMA B>
ystd::cout << STRVX(type<A COMMA B>) << std::endl;
se imprimirátype<A , B>
. (STRV
es para "variadic stringify" ySTRVX
es para "expandido variadic stringify".)COMMA
macro en primer lugar. Eso es con lo que terminé.Si su preprocesador admite macros variadic:
De lo contrario, es un poco más tedioso:
fuente
Solo define
FOO
comoLuego invocalo siempre entre paréntesis alrededor del argumento de tipo, por ejemplo
Por supuesto, puede ser una buena idea ejemplificar las invocaciones en un comentario sobre la definición de macro.
fuente
UNPACK
hago cuando se usa así) UNPACK type name
? ¿Por quétype
obtiene el tipo correctamente cuando se usa) UNPACK type name
? ¿Qué diablos está pasando aquí?Hay al menos dos formas de hacer esto. Primero, puede definir una macro que tome múltiples argumentos:
si lo hace, es posible que termine definiendo más macros para manejar más argumentos.
En segundo lugar, puede poner paréntesis alrededor del argumento:
si lo hace, puede encontrar que los paréntesis adicionales arruinan la sintaxis del resultado.
fuente
Esto es posible con P99 :
El código anterior elimina efectivamente solo la última coma en la lista de argumentos. Verifique con
clang -E
(P99 requiere un compilador C99).fuente
La respuesta simple es que no puedes. Este es un efecto secundario de la elección de
<...>
argumentos de plantilla; el<
y>
también aparecen en contextos desequilibradas por lo que el mecanismo de macro no podría extenderse a manejarlos como se maneja paréntesis. (Algunos de los miembros del comité habían abogado por una ficha diferente, por ejemplo(^...^)
, pero no pudieron convencer a la mayoría de los problemas con el uso<...>
).fuente
(^...^)
esta es una cara feliz :)