CREATE_CLASS(Person, (const char*, name), (int, age), (float, height))
C'est l'option la plus facile à utiliser, car la syntaxe du préprocesseur gère les parenthèses équilibrées, de telle sorte que, par exemple, les fichiers de type (const char*, name)
est un argument unique pour la macro, bien que contenant une virgule.
Une solution simple serait donc de fournir des macros enveloppantes qui acceptent un argument de la forme (type, varname)
et transmettez ses éléments à vos macros à deux arguments :
#define DECL_VAR(type,var)\
type _##var;
#define DECL_VAR_PAIR(pair)\
DECL_VAR pair
#define DECL_GETSET(type,var)\
type get_##var() const {return _##var;}\
void set_##var(type val) {_##var = val;}
#define DECL_GETSET_PAIR(pair)\
DECL_GETSET pair
#define CREATE_CLASS(C, ...)\
class C {\
private:\
MAP(DECL_VAR_PAIR, __VA_ARGS__)\
public:\
MAP(DECL_GETSET_PAIR, __VA_ARGS__)\
};
CREATE_CLASS(Person, (const char*, name), (int, age), (float, height))
Ainsi, par exemple, lorsque l'expansion de MAP(DECL_VAR_PAIR, __VA_ARGS__)
dans le dernier CREATE_CLASS
passe l'argument unique (int, age)
a DECL_VAR_PAIR
Les étapes de l'expansion comprennent :
DECL_VAR_PAIR((int, age))
DECL_VAR(int, age) // since DECL_VAR_PAIR(x) is just DECL_VAR then x
int _##age;
int _age;
Cependant, si vous avez un tas de choses à faire avec les arguments appariés, la création de toutes ces macros wrapper pourrait devenir encombrante. Au lieu de cela, nous pouvons ajouter un MAP
-qui s'attend à ce que ses arguments soient des listes entre parenthèses. Tout d'abord, remarquez que dans <map.h>
les étapes qui appliquent réellement une macro à l'un des arguments sont étroitement liées à l'étape principale de l'application de la macro. MAP
macro :
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP1)(f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT(peek, MAP0)(f, peek, __VA_ARGS__)
#define MAP(f, ...) EVAL(MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
Si l'argument x
est déjà entre parenthèses autour d'une liste d'arguments à passer à la macro f
nous voulons simplement que les versions parallèles évitent d'ajouter les parenthèses autour de x
:
#define MAP_TUPLES0(f, x, peek, ...) f x MAP_NEXT(peek, MAP_TUPLES1)(f, peek, __VA_ARGS__)
#define MAP_TUPLES1(f, x, peek, ...) f x MAP_NEXT(peek, MAP_TUPLES0)(f, peek, __VA_ARGS__)
#define MAP_TUPLES(f, ...) EVAL(MAP_TUPLES1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
J'ai appelé ça MAP_TUPLES
plutôt que MAP_PAIRS
parce que ce n'est pas vraiment limité aux paires. Elle peut passer des listes d'arguments de n'importe quelle taille à n'importe quelle macro, tant que le nombre de paramètres de la macro correspond. Vous pouvez même utiliser une macro variadique avec des listes d'arguments de tailles différentes.
Une utilisation de cette MAP_TUPLES
pour obtenir votre CREATE_CLASS
en supposant que l'original DECL_VAR
y DECL_GETSET
on dirait :
#define CREATE_CLASS(C, ...)\
class C {\
private:\
MAP_TUPLES(DECL_VAR, __VA_ARGS__)\
public:\
MAP_TUPLES(DECL_GETSET, __VA_ARGS__)\
};
CREATE_CLASS(Person, (const char*, name), (int, age), (float, height))
Voir le exemple complet sur coliru .