Как использовать boost препроцессор для генерации аксессоров?

Например

class A
{
int m_x;
float m_y;
double m_z;

int x() const {return m_x;}
float y() const {return m_y;}
double z() const {return m_z;}
};

становится как

class A
{
MY_MACRO((int)(float)(double), (x)(y)(z));
};

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

3

Решение

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

1-й подход:

//two different sequences
struct A
{
MY_MACRO1((int)(float)(double),(x)(y)(z))
};

Я думаю, что этот подход дает менее страшный макрос:

#define DECLARE_DATA_MEMBER1(R,TYPES,INDEX,NAME) \
BOOST_PP_SEQ_ELEM(INDEX,TYPES) BOOST_PP_CAT(m_,NAME);

#define DEFINE_ACCESSOR1(R,TYPES,INDEX,NAME) \
BOOST_PP_SEQ_ELEM(INDEX,TYPES) NAME(){ return BOOST_PP_CAT(m_,NAME); }

#define MY_MACRO1(TYPES,NAMES) \
BOOST_PP_SEQ_FOR_EACH_I(DECLARE_DATA_MEMBER1,TYPES,NAMES) \
public: \
BOOST_PP_SEQ_FOR_EACH_I(DEFINE_ACCESSOR1,TYPES,NAMES)

MY_MACRO получает две последовательности: TYPES а также NAMES, Для того, чтобы объявить членов данных я использую BOOST_PP_SEQ_FOR_EACH_I на последовательности NAMES используя макрос DECLARE_DATA_MEMBER1 и имея последовательность TYPES как данные. Это «вызывает» DECLARE_DATA_MEMBER1 с 4 параметрами: R который не используется (и я понятия не имею, что он делает), TYPES (последовательность типов), INDEX (сообщает, в какой итерации мы сейчас находимся, начиная с 0), и NAME (элемент оригинала NAMES последовательность, которая соответствует этой итерации).
«Тела» DECLARE_DATA_MEMBER1 а также DEFINE_ACCESSOR1 просты, мы просто получаем INDEXй элемент в последовательности типов и конкатенация m_ с NAME,


2-й подход:

//just one sequence but you need to put two sets of parentheses around each pair
struct B
{
MY_MACRO2(((int, x))((float,y))((double,z)))
};

Это все еще довольно просто, но неудобно использовать двойные скобки.

#define DECLARE_DATA_MEMBER2(R,_,TYPE_AND_NAME) \
BOOST_PP_TUPLE_ELEM(2,0,TYPE_AND_NAME) BOOST_PP_CAT(m_,BOOST_PP_TUPLE_ELEM(2,1,TYPE_AND_NAME));

#define DEFINE_ACCESSOR2(R,_,TYPE_AND_NAME) \
BOOST_PP_TUPLE_ELEM(2,0,TYPE_AND_NAME) BOOST_PP_TUPLE_ELEM(2,1,TYPE_AND_NAME)(){ return BOOST_PP_CAT(m_,BOOST_PP_TUPLE_ELEM(2,1,TYPE_AND_NAME)); }

#define MY_MACRO2(TYPES_AND_NAMES) \
BOOST_PP_SEQ_FOR_EACH(DECLARE_DATA_MEMBER2,_,TYPES_AND_NAMES) \
public: \
BOOST_PP_SEQ_FOR_EACH(DEFINE_ACCESSOR2,_,TYPES_AND_NAMES)

На этот раз есть только одна последовательность, поэтому нам не понадобится индекс в вспомогательных макросах. По этой причине BOOST_PP_SEQ_FOR_EACH используется в TYPES_AND_NAMES с использованием макроса DECLARE_DATA_MEMBER2 и без передачи каких-либо дополнительных данных. Этот макрос получает три «аргумента»: R снова не используется, _ (или же DATAтакже не используется здесь), и TYPE_AND_NAME (кортеж в форме (TYPE,NAME)).
В «телах» двух вспомогательных макросов BOOST_PP_TUPLE_ELEM используется для получения либо типа (с индексом = 0), либо имени (с индексом = 1). Этому макросу необходимо передать размер кортежа, индекс нужного элемента и кортеж.


3-й подход:

//one sequence but the macro is more complex
struct C
{
MY_MACRO3((int,x)(float,y)(double,z))
};

Этот макрос сильно заимствует из BOOST_FUSION_ADAPT_STRUCT и подобные макросы.

//Heavily "inspired" from BOOST_FUSION_ADAPT_STRUCT
#define CREATE_MY_MACRO_PLACEHOLDER_FILLER_0(X, Y)  \
((X, Y)) CREATE_MY_MACRO_PLACEHOLDER_FILLER_1
#define CREATE_MY_MACRO_PLACEHOLDER_FILLER_1(X, Y)  \
((X, Y)) CREATE_MY_MACRO_PLACEHOLDER_FILLER_0
#define CREATE_MY_MACRO_PLACEHOLDER_FILLER_0_END
#define CREATE_MY_MACRO_PLACEHOLDER_FILLER_1_END

#define DECLARE_DATA_MEMBER3(R,_,TYPE_AND_NAME) \
BOOST_PP_TUPLE_ELEM(2,0,TYPE_AND_NAME) BOOST_PP_CAT(m_,BOOST_PP_TUPLE_ELEM(2,1,TYPE_AND_NAME));

#define DEFINE_ACCESSOR3(R,_,TYPE_AND_NAME) \
BOOST_PP_TUPLE_ELEM(2,0,TYPE_AND_NAME) BOOST_PP_TUPLE_ELEM(2,1,TYPE_AND_NAME)(){ return BOOST_PP_CAT(m_,BOOST_PP_TUPLE_ELEM(2,1,TYPE_AND_NAME)); }

#define MY_MACRO3(TYPES_AND_NAMES) \
BOOST_PP_SEQ_FOR_EACH(DECLARE_DATA_MEMBER3,_,BOOST_PP_CAT(CREATE_MY_MACRO_PLACEHOLDER_FILLER_0 TYPES_AND_NAMES,_END)) \
public: \
BOOST_PP_SEQ_FOR_EACH(DEFINE_ACCESSOR3,_,BOOST_PP_CAT(CREATE_MY_MACRO_PLACEHOLDER_FILLER_0 TYPES_AND_NAMES,_END))

При таком подходе вспомогательные макросы в основном не меняются. Единственное (большое) отличие состоит в том, что последовательность, используемая в for_each, не просто TYPES_AND_NAMES но BOOST_PP_CAT(CREATE_MY_MACRO_PLACEHOLDER_FILLER_0 TYPES_AND_NAMES,_END), Это умный трюк, чтобы заставить двойные скобки. Это работает так:

CREATE_MY_MACRO_PLACEHOLDER_FILLER_0(int,x)(float,y)_END
//CREATE_MY_MACRO_PLACEHOLDER_FILLER_0(A,B)->((A,B))CREATE_MY_MACRO_PLACEHOLDER_FILLER_1
((int,x))CREATE_MY_MACRO_PLACEHOLDER_FILLER_1(float,y)_END
//CREATE_MY_MACRO_PLACEHOLDER_FILLER_1(A,B)->((A,B))CREATE_MY_MACRO_PLACEHOLDER_FILLER_0
((int,x))((float,y))CREATE_MY_MACRO_PLACEHOLDER_FILLER_0_END
//CREATE_MY_MACRO_PLACEHOLDER_FILLER_0_END->
((int,x))((float,y))

Бег по колиру.

10

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


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector