2

我正在尝试创建一个将定义和初始化静态数据的“C”宏(不是 C++)。

例如:

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)
    )
);

将导致“C”预处理器创建:

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}};

我尝试使用 Boost 预处理器

http://www.boost.org/doc/libs/1_54_0/libs/preprocessor/doc/

但我不太清楚如何使这项工作。我的宏停止扩展。我怀疑具有任意深度嵌套的问题的递归性质就是原因。

我读到的关于让预处理器递归的解决方案要么不起作用,要么关于如何让递归工作的描述不够清楚,无法实现一个可行的解决方案。

这是我到目前为止所拥有的:

#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)                           \
    }

谢谢。

4

1 回答 1

1

它可以在没有 boost-preprocessor 的情况下完成。

你实际上不需要递归。只是一个循环来迭代宏参数两次。

我冒昧地稍微修改了语法,以允许在类型和初始化程序中使用逗号,以防有人决定将它与 C++ 一起使用。

STATIC_CONST_STRUCT
(
    A, a, 
    MEMBER_DATA(a, const char *) "Hello, a"
    MEMBER_DATA(b, const char *) "Hello, b"
    MEMBER_STRUCT
    (
        C, c, 
        MEMBER_DATA(d, const char *) "Hello, d"
        MEMBER_DATA(e, int) 42
    )
)

这扩展为:

static const struct A
{
    const char *a;
    const char *b;
    struct C
    {
        const char *d;
        int e;
    } c;
} a =
{
    "Hello, a",
    "Hello, b",
    {
        "Hello, d",
        42,
    },
};

执行:

#define STATIC_CONST_STRUCT(type_, name_, ...) \
    static const struct type_ { \
        END( LOOP_DECL_0 (__VA_ARGS__) ) \
    } name_ = { \
        END( LOOP_INIT_0 (__VA_ARGS__) ) \
    };

#define MEMBER_DATA(name_, ...) )(var,name_,(__VA_ARGS__),
#define MEMBER_STRUCT(type_, name_, ...) )(open,type_ __VA_ARGS__ )(close,name_

#define IDENTITY(...) __VA_ARGS__

#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x##y

#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END

#define LOOP_DECL_0() LOOP_DECL_A
#define LOOP_DECL_A(...) LOOP_DECL_BODY(__VA_ARGS__) LOOP_DECL_B
#define LOOP_DECL_B(...) LOOP_DECL_BODY(__VA_ARGS__) LOOP_DECL_A
#define LOOP_DECL_0_END
#define LOOP_DECL_A_END
#define LOOP_DECL_B_END
#define LOOP_DECL_BODY(action_, ...) CAT(LOOP_DECL_BODY_, action_)(__VA_ARGS__)
#define LOOP_DECL_BODY_var(name_, type_, ...) IDENTITY type_ name_;
#define LOOP_DECL_BODY_open(type_) struct type_ {
#define LOOP_DECL_BODY_close(name_) } name_;

#define LOOP_INIT_0() LOOP_INIT_A
#define LOOP_INIT_A(...) LOOP_INIT_BODY(__VA_ARGS__) LOOP_INIT_B
#define LOOP_INIT_B(...) LOOP_INIT_BODY(__VA_ARGS__) LOOP_INIT_A
#define LOOP_INIT_0_END
#define LOOP_INIT_A_END
#define LOOP_INIT_B_END
#define LOOP_INIT_BODY(action_, ...) CAT(LOOP_INIT_BODY_, action_)(__VA_ARGS__)
#define LOOP_INIT_BODY_var(name_, type_, ...) __VA_ARGS__,
#define LOOP_INIT_BODY_open(type_) {
#define LOOP_INIT_BODY_close(name_) },

如果与 C++ 一起使用,IDENTITY type_则应包含在std::type_identity_t<...>其中以允许使用诸如函数指针之类的类型,而无需对它们进行类型定义。void (*)() foo;是非法的,虽然std::type_identity_t<void (*)()> foo;是可以的。

于 2021-12-27T21:03:18.417 回答