Perché le parentesi angolari possono anche rappresentare (o verificarsi) il confronto operatori <
, >
, <=
e >=
, l'espansione macro non può ignorare le virgole tra parentesi angolari come fa tra parentesi. (Questo è un problema anche per parentesi quadre e graffe, anche se quelli normalmente si verificano come coppie bilanciate.) È possibile racchiudere l'argomento macro in parentesi:
FOO((std::map<int, int>), map_var);
Il problema è quindi che il parametro rimane racchiusa tra parentesi all'interno della macro espansione, che impedisce di essere letto come un tipo nella maggior parte dei contesti.
Un bel trucco per aggirare questo è che in C++, è possibile estrarre un TypeName da un nome di tipo tra parentesi usando un tipo di funzione:
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
FOO((std::map<int, int>), map_var);
Perché la formazione di tipi di funzione ignora parentesi in più, è possibile utilizzare questa macro con o senza parentesi in cui il nome del tipo non include una virgola:
FOO((int), int_var);
FOO(int, int_var2);
In C, naturalmente, questo non è necessario perché i nomi di tipo non possono contenere virgole fuori parentesi. Così, per una macro cross-language si può scrivere:
#ifdef __cplusplus__
template<typename T> struct argument_type;
template<typename T, typename U> struct argument_type<T(U)> { typedef U type; };
#define FOO(t,name) argument_type<void(t)>::type name
#else
#define FOO(t,name) t name
#endif
Immagino che tu debba sfuggire ai personaggi con un significato per renderli letterali. – Jite
Almeno in C++, puoi inserire un typedef ovunque, quindi non sono sicuro del perché tu dici che deve essere "in anticipo". –