如何使用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));
};
请使用 boost 预处理器序列来执行此操作,因为此宏将与其他已使用 boost 预处理器序列的现有宏组合.
Please use boost prerocessor sequence to do it because this macro will combine with other existing macros which already use boost preprocesor sequence.
推荐答案
Disclaimer: 即使您对这个答案感到满意,您也应该等待,以防出现更好的答案,因为我远非专家,这些可能不会成为最好的方法.
Disclaimer:You should probably wait in case a better answer appears even if you are satisfied with this answer, because I'm far from an expert and these may not be the best approaches.
第一种方法:
//two different sequences
struct A
{
MY_MACRO1((int)(float)(double),(x)(y)(z))
};
我认为这种方法提供了看起来不那么可怕的宏:
I think this approach gives the less scary-looking macro:
#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
.为了声明数据成员,我在序列 NAMES
上使用了 BOOST_PP_SEQ_FOR_EACH_I
使用宏 DECLARE_DATA_MEMBER1
并具有序列 TYPES代码> 作为数据.这调用"带有 4 个参数的
DECLARE_DATA_MEMBER1
:R
未使用(我不知道它做什么),TYPES
(序列类型)、INDEX
(告诉我们现在处于哪个迭代中,从 0 开始)和 NAME
(原始 NAMES
序列的元素对应于本次迭代).DECLARE_DATA_MEMBER1
和 DEFINE_ACCESSOR1
的主体"很简单,我们只需获取类型序列中的第 INDEX
个元素,并连接 m_
和 NAME
.
MY_MACRO
gets two sequences: TYPES
and NAMES
. In order to declare the data members I use a BOOST_PP_SEQ_FOR_EACH_I
on the sequence NAMES
using the macro DECLARE_DATA_MEMBER1
and having the sequence TYPES
as data. This "invokes" DECLARE_DATA_MEMBER1
with 4 parameters: R
which is unused (and I have no idea what it does), TYPES
(the sequence of types), INDEX
(tells in which iteration we are right now, starting at 0), and NAME
(the element of the original NAMES
sequence that corresponds with this iteration).
The "bodies" of DECLARE_DATA_MEMBER1
and DEFINE_ACCESSOR1
are simple, we simply get the INDEX
th element in the types sequence, and concatenate m_
with NAME
.
第二种方法:
//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)))
};
这个还是比较简单的,但是有使用双括号的不便.
This one is still fairly simple, but has the inconvenient of having to use double parentheses.
#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
用于使用宏 DECLARE_DATA_MEMBER2
的 TYPES_AND_NAMES 并且不传递任何额外的数据.该宏接收三个参数":R
再次未使用,_
(或 DATA
,此处也未使用)和 TYPE_AND_NAME
((TYPE,NAME)
形式的元组).
在两个辅助宏的主体"中,BOOST_PP_TUPLE_ELEM
用于获取类型(索引 = 0)或名称(索引 = 1).这个宏需要传递元组的大小,你想要的元素的索引和元组.
This time there is only one sequence so we won't need the index in the helper macros. For this reason BOOST_PP_SEQ_FOR_EACH
is used on TYPES_AND_NAMES using the macro DECLARE_DATA_MEMBER2
and without passing any extra data. This macro receives three "arguments": R
again unused, _
(or DATA
, also unused here), and TYPE_AND_NAME
(a tuple in the form (TYPE,NAME)
).
In the "bodies" of the two helper macros BOOST_PP_TUPLE_ELEM
is used to get either the type(with index=0) or the name(with index=1). This macro needs to be passed the size of the tuple, the index of the element you want and the tuple.
第三种方法:
//one sequence but the macro is more complex
struct C
{
MY_MACRO3((int,x)(float,y)(double,z))
};
这个宏大量借鉴了 BOOST_FUSION_ADAPT_STRUCT
和类似的宏.
This macro borrows heavily from BOOST_FUSION_ADAPT_STRUCT
and similar macros.
//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)
.这是强制使用双括号的巧妙技巧.它是这样工作的:
In this approach the helper macros are basically unchanged. The only (big) difference is that the sequence used in the for_each is not simply TYPES_AND_NAMES
but BOOST_PP_CAT(CREATE_MY_MACRO_PLACEHOLDER_FILLER_0 TYPES_AND_NAMES,_END)
. This is a clever trick to force the double parentheses. It works like this:
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))
<小时>
在 Coliru 上运行.
相关文章