Boost logo

Boost Users :

Subject: [Boost-users] Preprocessor Recursion
From: Mitch Besser (bessermt_at_[hidden])
Date: 2013-10-25 15:53:08


I'm trying to create a 'C' macro that will define and initialize static
data.

For example:

    STATIC_CONST_STRUCT
    (
        A, a,
        MEMBER_DATA(CONST_STR, a, "Hello, a")
        MEMBER_DATA(CONST_STR, b, "Hello, b")
        MEMBER_STRUCT
        (
            C, c,
            MEMBER_DATA(CONST_STR, d, "Hello, d")
            MEMBER_DATA(CONST_INT, e, 1)
        )
    );

Would cause the 'C' preprocessor to create:

    static const struct A
    {
        CONST_STR a;
        CONST_STR b;
        struct C
        {
            CONST_STR d;
            CONST_INT e;
        } c;
    } =
    {"Hello, a", "Hello, b", {"Hello, d", 1}};

If I could use C++, this would be easy, but I'm using 'C' and it would be
very helpful to have the initialization along with the declaration.

I can't quite figure out how to make this work. My macros stop expanding. I
suspect the recursive nature of the problem having an arbitrarily deep
nesting is why. If it helps, I do have a maximum depth for the nesting.

I've tried reading the docs and learn more about recursion, but I can't
seem to find a solution. I suspect I'm close.

Here's what I have so far (not claiming this is a good solution, so feel
free to suggest anything that would make this better):

    #define MEMBER_DATA_TAG 0
    #define MEMBER_STRUCT_TAG 1

    #define MEMBER_TAG(MEMBER) BOOST_PP_SEQ_ELEM(0, MEMBER)

    #define MEMBER_DATA_TYPE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(1, MEMBER_DATA)
    #define MEMBER_DATA_NAME(MEMBER_DATA) BOOST_PP_SEQ_ELEM(2, MEMBER_DATA)
    #define MEMBER_DATA_VALUE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(3, MEMBER_DATA)

    #define MEMBER_STRUCT_TYPE(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(1,
MEMBER_STRUCT)
    #define MEMBER_STRUCT_NAME(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(2,
MEMBER_STRUCT)
    #define MEMBER_STRUCT_MEMBER_SEQ(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(3,
MEMBER_STRUCT)

    #define MEMBER_DATA(TYPE, NAME, VALUE)
((MEMBER_DATA_TAG)(TYPE)(NAME)(VALUE))
    #define MEMBER_STRUCT(TYPE, NAME, MEMBER_SEQ)
((MEMBER_STRUCT_TAG)(TYPE)(NAME)(MEMBER_SEQ))

    #define IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM)
BOOST_PP_EQUAL(MEMBER_TAG(MEMBER_SEQ_ELEM), MEMBER_STRUCT_TAG)

    #define MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ)
         \
        struct TYPE
         \
        {
         \
            BOOST_PP_SEQ_FOR_EACH(MEMBER_ELEM_DECLARE, BOOST_PP_EMPTY(),
MEMBER_SEQ) \
        } NAME

    #define MEMBER_ELEM_DECLARE(_r, _data, MEMBER_SEQ_ELEM) \
        BOOST_PP_IIF \
        ( \
            IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \
            MEMBER_STRUCT_DECLARE \
            ( \
                MEMBER_STRUCT_TYPE(MEMBER_SEQ_ELEM), \
                MEMBER_STRUCT_NAME(MEMBER_SEQ_ELEM), \
                MEMBER_STRUCT_MEMBER_SEQ(MEMBER_SEQ_ELEM) \
            ), \
            MEMBER_DATA_DECLARE \
            ( \
                MEMBER_DATA_TYPE(MEMBER_SEQ_ELEM), \
                MEMBER_DATA_NAME(MEMBER_SEQ_ELEM), \
                MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \
            ) \
        );

    #define MEMBER_DATA_DECLARE(TYPE, NAME, VALUE) TYPE NAME

    #define MEMBER_VALUE_INIT(MEMBER_SEQ) \
        BOOST_PP_SEQ_FOR_EACH_I(MEMBER_VALUE_INIT_DECLARE,
BOOST_PP_EMPTY(), MEMBER_SEQ);

    #define MEMBER_VALUE_INIT_DECLARE(_r, _data, i, MEMBER_SEQ_ELEM) \
        BOOST_PP_COMMA_IF(i) \
        BOOST_PP_IIF \
        ( \
            IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \
            {MEMBER_VALUE_INIT(MEMBER_SEQ_ELEM)}, \
            MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \
        )

    #define STATIC_CONST_STRUCT(TYPE, NAME, MEMBER_SEQ) \
        static const MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) = \
        { \
             MEMBER_VALUE_INIT(MEMBER_SEQ) \
        }

Thanks.

-- 
"лось и белка"


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