用于类

时间:2016-10-22 20:33:21

标签: c++ boost macros

我经常描述现有的结构,我需要任何方法来自动生成结构图......

例如,我的结构很小:

struct SExampleBox
{
  int   x;    //0x0000
  int   y;    //0x0004
  float size; //0x0008

}; Size=0x000C

我的想法是将其描述为:(使用宏或者可能是boost.preprocessor)

STRUCT_BEGIN(SExampleBox)
  MEMBER(int, x);
  MEMBER(int, y);
  MEMBER(float size);
STRUCT_END

将其自动展开为:

struct SExampleBox
{
  int x;
  int y;
  float size;
};

void DUMP__SExampleBox(SExampleBox *obj)
{
  printf("%p > SExampleObj:\n", obj);
  printf("  0x%04x - int x = %d\n", offsetof(SExampleObj, x), obj->x);
  printf("  0x%04x - int y = %d\n", offsetof(SExampleObj, y), obj->y);
  printf("  0x%04x - float size = %f\n", offsetof(SExampleObj, size), obj->size);
}

调用DUMP__SExampleBox(test);并获得示例输出:

0x00402000 > SExampleObj:
  0x0000 - int x = 100
  0x0004 - int y = 50
  0x0008 - float size = 200.000f

有没有可行的方法呢? 谢谢!

1 个答案:

答案 0 :(得分:0)

对值格式化juggle不太满意,但这是可调整的。

语法如下:

DECLARE_STRUCT(SExampleBox,
    (int, x)
    (int, y)
    (float, size)
)

int main(int, char**) {
    SExampleBox o{1, 2, 3.14f};
    dump(&o);
}

现在,实施。首先,我们需要一个效用函数来为Boost.PP序列添加括号,将(a)(b)转换为((a))((b))

#define glk_pp_detail_doubleSeqParens_0(...)\
     ((__VA_ARGS__)) glk_pp_detail_doubleSeqParens_1

#define glk_pp_detail_doubleSeqParens_1(...)\
     ((__VA_ARGS__)) glk_pp_detail_doubleSeqParens_0

#define glk_pp_detail_doubleSeqParens_0_end
#define glk_pp_detail_doubleSeqParens_1_end

#define glk_pp_doubleSeqParens(seq)\
    BOOST_PP_CAT(glk_pp_detail_doubleSeqParens_0 seq, _end)

然后我们将构建struct声明的框架和相应的函数:

#define DECLARE_STRUCT(name_, fields_) \
    struct name_ { \
        BOOST_PP_SEQ_FOR_EACH(DETAIL_DECLARE_FIELD, name_, glk_pp_doubleSeqParens(fields_)) \
    }; \
    void dump(name_ *obj_) { \
        ::std::printf("%p > " BOOST_PP_STRINGIZE(name_) ":\n", static_cast<void*>(obj_)); \
        BOOST_PP_SEQ_FOR_EACH(DETAIL_PRINT_FIELD, name_, glk_pp_doubleSeqParens(fields_)) \
    }

来自glk_pp_doubleSeqParens的双括号可以将元组序列(type, name)(type, name)传递给BOOST_PP_SEQ_FOR_EACH,否则会因为逗号而阻塞它。

现在只需为每个结构成员形成有效的成员声明和打印语句:

#define DETAIL_DECLARE_FIELD(r, structName_, typeAndName_) \
    BOOST_PP_TUPLE_ELEM(0, typeAndName_) BOOST_PP_TUPLE_ELEM(1, typeAndName_);

#define DETAIL_PRINT_FIELD_1(structName_, type_, name_) \
    ::std::printf("  0x%04zx - " BOOST_PP_STRINGIZE(type_) " " BOOST_PP_STRINGIZE(name_) " = ", offsetof(structName_, name_)); \
    ::detail_printValue(obj_->name_);

#define DETAIL_PRINT_FIELD(r, structName_, typeAndName_) \
    DETAIL_PRINT_FIELD_1(structName_, BOOST_PP_TUPLE_ELEM(0, typeAndName_), BOOST_PP_TUPLE_ELEM(1, typeAndName_))

为每个值选择适当的格式参数有点笨重。我已选择将其推迟到只打印值和换行符的重载集,但您也可以动态构造格式字符串并使用单个printf

void detail_printValue(float const &v) { std::printf("%f\n", v); }
void detail_printValue(int const &v)   { std::printf("%d\n", v); }

瞧! See it live on Coliru