Boost logo

Boost Users :

Subject: Re: [Boost-users] fusion struct adapt macro, construct the struct from a fusion vector
From: Nat Goodspeed (nat_at_[hidden])
Date: 2010-01-20 16:24:06


Joel de Guzman wrote:

> Or, if you can wait a bit, I do intend to write an intrusive version of
> the FUSION_ADAPT_STRUCT which also generates the struct along with
> the constructors and assignment to/from fusion sequences. I dunno,
> perhaps you can persuade a fusion guru to write the code (Christopher)? :-)

This isn't all of the above, but the attached worked for me as of Boost
1.35.0...


#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/transform.hpp>
// only for testing
#include <iostream>

// BOOST_FUSION_BUILD_STRUCT() borrows its syntax from
// BOOST_FUSION_ADAPT_STRUCT(). The general idea is that you write the same
// code you'd have written for BOOST_FUSION_ADAPT_STRUCT(), but the _BUILD_
// variant actually declares the struct for you as well. The trouble with
// BOOST_FUSION_ADAPT_STRUCT's member syntax is that it's a PP sequence of
// tuples. BOOST_PP_SEQ_FOR_EACH() handles sequences of single tokens fine,
// but a sequence of tuples breaks it. An implementation based on
// BOOST_PP_SEQ_FOR_EACH() would require double parentheses, e.g.:
// BOOST_FUSION_BUILD_STRUCT(employee, ((std::string, name))((int, age)))
// But clearly BOOST_FUSION_ADAPT_STRUCT() manages to avoid that, so we borrow
// its implementation. Thanks to Paul Mensonides and Joel de Guzman!

#define BOOST_FUSION_BUILD_STRUCT(name, bseq) \
    BOOST_FUSION_BUILD_STRUCT_I( \
        name, BOOST_PP_CAT(BOOST_FUSION_BUILD_STRUCT_X bseq, 0)); \
    BOOST_FUSION_ADAPT_STRUCT(name, bseq) \
    /***/

#define BOOST_FUSION_BUILD_STRUCT_X(x, y) ((x, y)) BOOST_FUSION_BUILD_STRUCT_Y
#define BOOST_FUSION_BUILD_STRUCT_Y(x, y) ((x, y)) BOOST_FUSION_BUILD_STRUCT_X
#define BOOST_FUSION_BUILD_STRUCT_X0
#define BOOST_FUSION_BUILD_STRUCT_Y0

// BOOST_FUSION_BUILD_STRUCT_I generates the overarching structure and uses
// SEQ_FOR_EACH_I to generate the "linear" substructures.
// Thanks to Paul Mensonides for the PP macro help.

#define BOOST_FUSION_BUILD_STRUCT_I(name, seq) \
    struct name \
    { \
        name(BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(BOOST_FUSION_BUILD_STRUCT_P, ~, seq))): \
             BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM(BOOST_FUSION_BUILD_STRUCT_MI, ~, seq)) \
        {} \
        BOOST_PP_SEQ_FOR_EACH_I(BOOST_FUSION_BUILD_STRUCT_C, ~, seq) \
    } \
    /***/

#define BOOST_FUSION_BUILD_STRUCT_P(r, ignore, xy) \
    BOOST_PP_TUPLE_ELEM(2, 0, xy) BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, xy), _) \
    /***/

#define BOOST_FUSION_BUILD_STRUCT_MI(r, ignore, xy) \
    BOOST_PP_TUPLE_ELEM(2, 1, xy)(BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2, 1, xy), _)) \
    /***/

#define BOOST_FUSION_BUILD_STRUCT_C(r, ignore, i, xy) \
    BOOST_PP_TUPLE_ELEM(2, 0, xy) BOOST_PP_TUPLE_ELEM(2, 1, xy); \
    /***/

// Example
BOOST_FUSION_BUILD_STRUCT(employee,
                          (std::string, name)
                          (int, age))

int main(int argc, char *argv[])
{
    employee Jane("Jane", 37);
    std::cout << "Name " << Jane.name << ", age " << Jane.age << '\n';
    return 0;
}


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