如何使用boost预处理器生成访问器? [英] How to use boost preprocessor to generate accessors?

查看:18
本文介绍了如何使用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 得到两个序列:TYPESNAMES.为了声明数据成员,我在序列 NAMES 上使用了 BOOST_PP_SEQ_FOR_EACH_I 使用宏 DECLARE_DATA_MEMBER1 并具有序列 TYPES 作为数据.这调用"带有 4 个参数的 DECLARE_DATA_MEMBER1:R 未使用(我不知道它做什么),TYPES(序列类型)、INDEX(告诉我们现在处于哪个迭代中,从 0 开始)和 NAME(原始 NAMES 序列的元素对应于本次迭代).
DECLARE_DATA_MEMBER1DEFINE_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 INDEXth 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 上运行.

这篇关于如何使用boost预处理器生成访问器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆