Parce que les crochets d'angle peuvent également représenter (ou apparaître dans) les opérateurs de comparaison <
, >
, <=
y >=
L'expansion des macros ne peut pas ignorer les virgules à l'intérieur des crochets comme elle le fait pour les parenthèses. (C'est également un problème pour les crochets et les accolades, même si ceux-ci se présentent généralement sous forme de paires équilibrées). Vous pouvez mettre l'argument de la macro entre parenthèses :
FOO((std::map<int, int>), map_var);
Le problème est alors que le paramètre reste entre parenthèses à l'intérieur de l'expansion de la macro, ce qui l'empêche d'être lu comme un type dans la plupart des contextes.
Une astuce intéressante pour contourner ce problème est qu'en C++, vous pouvez extraire un nom de type à partir d'un nom de type entre parenthèses en utilisant un type de fonction :
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);
Comme la formation des types de fonctions ignore les parenthèses supplémentaires, vous pouvez utiliser cette macro avec ou sans parenthèses lorsque le nom du type ne comporte pas de virgule :
FOO((int), int_var);
FOO(int, int_var2);
En C, bien sûr, ce n'est pas nécessaire car les noms de types ne peuvent pas contenir de virgules en dehors des parenthèses. Ainsi, pour une macro inter-langue, vous pouvez écrire :
#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