gpt4 book ai didi

c++ - 如何读取 C/C++ 中的结构类型

转载 作者:太空宇宙 更新时间:2023-11-04 01:35:25 26 4
gpt4 key购买 nike

我试图找到不同结构中任何给定变量的“类型”并能够读取它们。 (记住这是伪代码)

例如:

#include "stream.h" //a custom stream reader class I made

typedef unsigned char BYTE;

/***** SERIES OF DIFFERENT STRUCTS ******/

struct asset
{
char *name;
int size;
BYTE *data;
};

struct asset2
{
char *lang;
char *entry;
};

/*****************************************/


void readAsset( Enumerable<struct> &istruct)
{
foreach( object o in istruct )
{
switch( o )
{
case int:
&o = _stream->ReadInt32();
break;
case char:
&o = _stream->ReadChar();
break;
case *:
&o = _stream->ReadInt32();
break;
default: break;
}
}
}

我希望它能够执行以下操作:

asset a1;
asset2 a2;

readAsset( a1 );
readAsset( a2 );

并将文件中的所有信息传递给 a1 和 a2。

我想知道在 C/C++ 中是否有一种方法可以从结构中的任何对象获取数据类型,然后基于该类型进行读取?复杂的枚举有可能吗?对于糟糕的代码,我深表歉意,但我希望它更容易理解我正在尝试做的事情。

附加信息:

_stream 是一个指向我创建的 Stream 类的指针,类似于 .Net 中的 Stream Reader 它从文件中读取数据并根据读取的数据量提升其位置。

如果您不明白我在问什么,我很乐意重新表述。

最佳答案

如果不全部列出结构成员,就无法遍历结构成员。

您可以在编译时使用 C++11 中的 ::std::tuple 遍历结构之类的东西。

您也无法真正以那种方式打开类型。你可以做到,但你这样做的方法是让几个函数具有相同的名称,每个函数采用不同的参数类型。像这样的东西:

 void doRead(StreamType &stream, int &data)
{
data = stream.readInt32();
}
void doRead(StreamType &stream, char &data)
{
data = stream.readChar();
}
// etc...

然后您只需使用您的结构成员调用 doRead,然后编译器会根据类型神奇地选择正确的。

在 C++ 中,解决您在此处解决的问题的方法是序列化库。如果您可以控制写入的格式和读取的格式,则可以使用类似 protobuf 的方式。或 boost::serialization无需编写大量自己的代码即可相对轻松地完成此操作。

此外,您的代码还有一些问题。不要在标识符中使用前导 _ 字符。以 _ 开头的标识符保留供编译器或标准库实现使用。许多编译器都有特殊的关键字,这些关键字是编译器特定的语言扩展,以 _ 字符开头。使用带有前导 _ 字符的标识符可能会导致您的代码神秘地无法编译,并在某些环境中出现各种奇怪的难以理解的错误。


您可以获得类似于在编译时可枚举的结构的内容。但它很丑:

#include <tuple>
#include <string>
#include <vector>
#include <type_traits>

class asset : public ::std::tuple< ::std::string, ::std::vector<BYTE> >
{
public:
::std::string &name() { return ::std::get<0>(*this); }
const ::std::string &name() const { return ::std::get<0>(*this); }
::std::vector<BYTE> &data() { return ::std::get<1>(*this); }
const ::std::vector<BYTE> &data() const { return ::std::get<1>(*this); }
};

void writeToStream(Stream *out, const ::std::string &field)
{
out->writeString(field);
}
void writeToStream(Stream *out, const ::std::vector<BYTE> &field)
{
out->writeInt(field.size());
out->writeRaw(field.data(), field.size());
}

template <unsigned int fnum, typename... T>
typename ::std::enable_if< (fnum < sizeof...(T)), void >::type
writeToStream_n(Stream *out, const::std::tuple<T...> &field)
{
writeToStream(out, ::std::get<fnum>(field));
writeToStream_n<fnum+1, T...>(out, field);
}

template <unsigned int fnum, typename... T>
typename ::std::enable_if< (fnum >= sizeof...(T)) >::type
writeToStream_n(Stream *, const::std::tuple<T...> &)
{
}

template <typename... Tp>
void writeToStream(Stream *out, const ::std::tuple<Tp...> &composite)
{
writeToStream_n<0, Tp...>(out, composite);
}

void foo(Stream *out, const asset &a)
{
writeToStream(out, a);
}

请注意,asset 类型没有显式的 writeToStream。编译器将在运行时通过解压缩它派生自的 ::std::tuple 并写出每个单独的字段来编写它。

此外,如果您有裸指针,那么您正在编写糟糕的 C++。如果您要编写 C++,请编写惯用的、好的 C++。你想用运行时反射做的这整件事并不是做事的方式。

这就是我将你的 char *name 转换为 ::std::string 并且你的大小分隔 BYTE 数组的原因sizedata 字段到 ::std::vector 中。使用这些类型是编写 C++ 的惯用正确方法。不是像以前那样使用裸指针。此外,如果有两个字段具有高度相关的值(datasize),但没有任何行为或任何其他表明它们关联的字段,即使对于一个在运行时进行内省(introspection)以找出正确的事情的编译器。它不知道 data 指向的 BYTE 数组有多大,也不知道您决定将其编码为 size.

关于c++ - 如何读取 C/C++ 中的结构类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15306224/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com