CREATE_CLASS(Person, (const char*, name), (int, age), (float, height))
Это будет более простой вариант для работы, поскольку синтаксис препроцессора обрабатывает сбалансированные скобки таким образом, что, например, (const char*, name)
является единственным аргументом макроса, несмотря на то, что содержит запятую.
Таким образом, одним простым решением было бы предоставить макросы-обертки, которые принимают аргумент в форме (type, varname)
и передают его элементы вашим действительным макросам с двумя аргументами:
#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))
Так, например, когдарасширение MAP(DECL_VAR_PAIR, __VA_ARGS__)
в последней строке CREATE_CLASS
передает один аргумент (int, age)
в DECL_VAR_PAIR
, шаги расширения включают в себя:
DECL_VAR_PAIR((int, age))
DECL_VAR(int, age) // since DECL_VAR_PAIR(x) is just DECL_VAR then x
int _##age;
int _age;
Хотя, если у вас есть куча вещей, которые вы хотитеиз-за парных аргументов создание всех этих макросов-оберток может стать громоздким. Вместо этого мы можем добавить MAP
-подобный макрос, который ожидает, что его аргументы будут списками, заключенными в скобки. Во-первых, обратите внимание, что в <map.h>
шаги, которые фактически применяют макрос к одному из аргументов, тесно связаны с основным макросом MAP
:
#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))
Если аргумент x
уже является скобкамивокруг одного списка аргументов для передачи в макрос f
, мы просто хотим, чтобы параллельные версии пропускали добавление скобок вокруг 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))
Я назвал это MAP_TUPLES
вместо MAP_PAIRS
, потому чтоэто на самом деле не ограничивается парами. Он может передавать списки аргументов любого размера любому макросу, если совпадает количество параметров макроса. Вы даже можете использовать макрос с переменным списком аргументов различных размеров.
Использование этого MAP_TUPLES
для получения CREATE_CLASS
, при условии, что ваши исходные DECL_VAR
и DECL_GETSET
, выглядят так:
#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))
См. Полный пример в coliru .