$include_dir="/home/hyper-archives/boost-users/include"; include("$include_dir/msg-header.inc") ?>
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