除非您构建自己的元数据来描述结构,否则无法迭代结构的成员。C++ 编译器根本不会自动发出您需要的信息。
但是,通过一些宏魔术,您可以非常轻松地构建所需的元数据。很多年前我写了一些代码来做到这一点(实际上是一个完整的 Windows 自定义控件),我仍然一直在使用它。
基本技巧是使用一点宏魔术来获取编译器来帮助您构建元数据。
// this is the structure I want to iterate
typedef struct {
int foo;
char bar[16];
} StructIWantToIterate;
// this is the metadata I need for each field of the structure
typedef struct {
char * pszFieldName;
size_t oFieldOffset;
size_t cbFieldSize;
int eType;
} MyStructMeta;
// these are the field types I need to handle.
enum {
type_is_int,
type_is_char,
};
// these macros help to emit the metadata
#define NUMELMS(ary) (sizeof(ary)/(sizeof(ary)[0]))
#define FIELDOFF(tag,fld) ((size_t)&(((tag *)0)->fld))
#define FIELDSIZ(tag,fld) sizeof(((tag *)0)->fld)
#define STDFLD(tag,fld,as) #fld, FIELDOFF(tag,fld), FIELDSIZ(tag,fld), as
// now we declare the metadata for the StructIWantToIterate structure
#undef MYFLD
#define MYFLD(fld,as) STDFLD(StructIWantToIterate,fld,as)
static const MyStructMeta aMeta[] = {
MYFLD(foo, type_is_int), // expands to "foo", 0, sizeof(int), type_is_int
MYFLD(bar, type_is_char),// expands to "bar", sizeof(int), 16, type_is_char
};
// and when we want to do the iteration, assume ptr is a pointer to an instance
// of StructIWantToIterate
for (int ii = 0; ii < NUMELMS(aMeta); ++ii)
{
char szLine[100]; // pick your own worst case line size.
// get a pointer to the current field within the struct
void * pfld = ((byte*)ptr) + aMeta[ii].oFieldOffset;
// print out the field data based on the type_is_xxx information
switch (aMeta[ii].eType)
{
case type_is_int:
sprintf(szLine, "%s : %d", aMeta[ii].pszFieldName, *(int*)pfld);
break;
case type_is_char:
sprintf(szLine, "%s : %*s",
aMeta[ii].pszFieldName,
aMeta[ii].cbFieldSize,
pfld);
break;
}
// send it to the richedit control
RichEdit1->Lines->Append(asLine);
}