Boost logo

Boost Users :

Subject: Re: [Boost-users] Preprocessor sequence of "pairs"
From: Viatcheslav.Sysoltsev_at_[hidden]
Date: 2012-09-26 04:01:18


On Wed, 26 Sep 2012 07:52:24 +0200, <driscoll_at_[hidden]> wrote:

> I have a question about the use of the preprocessor library. I'll
> describe
> my ultimate goal in a moment, but I've simplified my first problem to the
> following. Also, I know what I'm doing looks a lot at first glance like
> Fusion's ADAPT_STRUCT, but I took a quick look at that documentation and
> I
> don't think it matches. However, if you disagree with me and think it
> does, or can suggest a totally different solution, feel free to describe
> how.
>
> == My problem ==
>
> I don't like C's struct syntax, so I'm trying to define my own.
> (</sarcasm> Really for purposes of this section I'm just doing this to
> figure out all the steps I'll need.)
>
> What I want to do is something like the following:
>
> #include <boost/preprocessor/seq/for_each.hpp>
>
> #define DEFINE_FIELD(r, os, field_pair) [....]
>
> #define DEFINE_STRUCT(struct_name, fields) \
> struct struct_name { \
> BOOST_PP_SEQ_FOR_EACH(DEFINE_FIELD, ~, fields) \
> }
>
> DEFINE_STRUCT(mystruct, (int, x)(int, y)(double, z))
>
> but this doesn't work, because the sequence is made up of pairs instead
> of
> single preprocessor arguments. (GCC complains about "macro
> "BOOST_PP_SEQ_SIZE_0" passed 2 arguments, but takes just 1" and same for
> PP_EXPR_IIF_0.)
>
> I can get it to work by double-parenthesizing the stuff in the sequence
> (saying "((int, x))((int, y))((double, z))") then defining DEFINE_FIELD
> as
> follows:
>
> #define DEFINE_FIELD_REAL(type, name) type name;
> #define DEFINE_FIELD(r, os, field_pair) DEFINE_FIELD_REAL field_pair
>
> but this is less than optimal. Is there a way that I can do this easily,
> or would I effectively have to re-implement SEQ_FOR_EACH? (And how hard
> would that be if it's necessary?)
>
>
> == What I'm actually trying to do ==
>
> What I'm actually doing is trying to write a macro that will define a
> function like the following:
>
> DEFINE_SERIALIZED_STRUCT(mystruct, (int, x)(int, y)(double, z))
> |
> V
> struct mystruct {
> int x;
> int y;
> double z;
> };
> void serialize(ostream & os, mystruct const & s) {
> os << "x: " << s.x << "\n";
> os << "y: " << s.y << "\n";
> os << "z: " << s.z << "\n";
> }
>
> (I didn't see a way to recover the field names from a Fusion-adapted
> struct -- from what I can tell, it more just seems to be a way to iterate
> over the fields.)

Hi,

the trick /I looked from fusion:)/ is to wrap every sequence member in an
additional () before passing it to the main macro:

#define
MY_SEQUENCE_CREATOR_0(...)
\
     ((__VA_ARGS__)) MY_SEQUENCE_CREATOR_1
#define
MY_SEQUENCE_CREATOR_1(...)
\
     ((__VA_ARGS__)) MY_SEQUENCE_CREATOR_0
#define MY_SEQUENCE_CREATOR_0_END
#define MY_SEQUENCE_CREATOR_1_END

And then you wrap call to your DEFINE_STRUCT:

#define _DEFINE_STRUCT(struct_name, fields) \
    struct struct_name { \
       BOOST_PP_SEQ_FOR_EACH(DEFINE_FIELD, ~, fields) \
    }
#define DEFINE_FIELD(r, data, field_tuple) \
        V_BOOST_PP_TUPLE_ELEM(0, field_tuple) V_BOOST_PP_TUPLE_ELEM(1,
field_tuple);

#define DEFINE_STRUCT(struct_name, fields) \
     _DEFINE_STRUCT(struct_name, \
        BOOST_PP_CAT(MY_SEQUENCE_CREATOR_0 fields,_END)) \

If I dont mistake it basically transforms
DEFINE_STRUCT(mystruct, (int, x)(int, y)(double, z))
into
_DEFINE_STRUCT(mystruct, ((int, x))((int, y))((double, z)))
so you get a single *tuple* as a parameter to your DEFINE_FIELD.
Eventually you can call another macro with this tuple, but I am not sure
whether this will be preprocessed as expected. I had troubles with it, so
I used V_BOOST_PP_TUPLE_ELEM (appeared first in boost 1.49) to extract
tuple elements in-place and it worked for me.

// I've heard there are some nasty troubles with msvc and variadic macros,
so you have an additional quest if you need to support msvc

-- Slava


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net