создать макрос для сбора токена (параметра) в список, один за другим

Я пытаюсь создать макрос, который генерирует указатель на экземпляр другого класса для обозначения направленного отношения.

//#define BIND(A,B) ?
//can be modified a little, top header
BIND(CAT,DOG)
BIND(CAT,TREE)
BIND(CAT,RAT)
BIND(DOG,TREE)
//#define MACRO_CAT (need?) ?
//#define MACRO_DOG (need?) ?

введите описание изображения здесь

Выше приведена соответствующая диаграмма. (В реальном случае, есть более 100 классов.)
Стрелка головы (красная) Right<>, Стрелка хвоста (зеленая) Left<>, (ниже фрагмента)

Возможно ли, что приведенный выше код создаст макрос MACRO_CAT/MACRO_DOG автоматически как это? : —

//v should not be modified
class Cat{
MACRO_CAT
/* expand to :-
Right<Dog> dogs;
Right<Tree> trees;
Right<Rat> rats;
*/
};
class Dog{
MACRO_DOG
/* expand to :-
Right<Tree> trees;
Left<Cat> cats;
*/
};

это повозка, запряженная волами Макро-магия была бы действительно полезна для поддержания отношений между объектами с максимальной производительностью.

Похоже X-макро это возможное решение, но у меня относительно низкий опыт по этому поводу.
Я также прочитал:

Просто грубое руководство / идея ценится. (полный код не нужен, но я не против)

Редактировать: В реальном случае BIND разбрасывает во многих заголовках.
Это пример #include поток (ниже #include верхний): —
введите описание изображения здесь

1

Решение

В этом решении я склонялся к TMP, а не к макросам.

Первый шаг — собрать все заявленные привязки. Возможно, можно было бы разрешить свободно объявлять привязки и разбрасывать их по другому коду. Однако потребуется некоторый способ сохранить и обновить состояние списка, что в значительной степени самая загадочная вещь, которую вы хотели бы сделать в C ++. Так что давайте не будем этого делать.

Файлы привязки будут иметь содержать только инструкции препроцессора и обращения к макросу BIND, следующее:

BIND(Cat, Dog)
BIND(Cat, Tree)
BIND(Cat, Rat)
BIND(Dog, Tree)

Другими словами, предварительно обработанные файлы должны содержать только замещенный вывод из BIND, Тогда мы можем сэндвич эти между bindTop.h а также bindBottom.h:

template <class...>
struct pack;

// Stuff in bindTop.h

#define BIND(T, U) \
pack<struct T, struct U>,

using AllBindings = pack<

// End of bindTop.h, beginning of the binding file(s)

BIND(Cat, Dog)
BIND(Cat, Tree)
BIND(Cat, Rat)
BIND(Dog, Tree)

// End of the binding file(s), beginning of bindBottom.h

void // Pairs up with the last comma,
// will be silently ignored in further processing
>;

#undef BIND

// Stuff in bindBottom.h

Теперь у нас есть наш список привязок внутри AllBindings,

Следующий шаг: как мы вводим член в класс? Я отказался от макроса и вместо этого использовал наследование членов. Таким образом, определение класса, как:

struct Cat  : WithBindings<Cat,  AllBindings> { };

… в конечном итоге наследует от нескольких структур, которые будут определять членов Right<Dog> dogs, Right<Tree> trees, а также Right<Rat> ratsи, таким образом, сможет получить к ним доступ почти так, как если бы они были его.

Но как объявить, что член типа Right<Dog> должен быть назван dogs? Макросы, конечно! Давайте сделаем пустые шаблоны для левых и правых базовых классов:

template <class T, class Binding>
struct MakeLeftMember { };

template <class T, class Binding>
struct MakeRightMember { };

И затем мы будем использовать макрос, чтобы специализировать их для каждого из наших классов, с именем класса и именем соответствующих членов:

#define BINDING_MEMBER_NAME(type_, memberName_) \
template <class T> struct MakeLeftMember<T, pack<type_, T>> { \
Left<type_> memberName_; \
}; \
template <class T> struct MakeRightMember<T, pack<T, type_>> { \
Right<type_> memberName_; \
}

Binding как ожидается, будет одним из pack<L, R> что мы определили с BIND, Теперь создаем экземпляр, например MakeLeftMember<T, pack<L, R>> отправит к специализации только если T является Rто есть привязка действительно является левой привязкой для T. Тогда специализация сгенерирует подходящее имя Left<L> член для наследования T, В остальных случаях базовый шаблон выбирается, и ничего не происходит.

Последнее недостающее звено конечно WithBindings<T, AllBindings>, который просто отправляет все привязки в создатели элементов и наследует полученные сгенерированные элементы:

template <class T, class... Bindings>
struct WithBindings<T, pack<Bindings...>>
: MakeLeftMember <T, Bindings>...
, MakeRightMember<T, Bindings>... { };

И там мы идем. Смотрите это в прямом эфире на Coliru!

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]