如何在C/ c++中通读结构体的类型
How to read through types of a struct in C/C++
我试图在不同的结构中找到任何给定变量的"类型",并能够读取它们。(记住这是伪代码)
例如:#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
和您的size
和data
字段表示的大小分隔的BYTE
数组转换为::std::vector
的原因。使用这些类型是编写c++的惯用正确方法。像你以前那样使用指针可不是。此外,如果有两个字段(data
和size
)具有强相关的值,但没有任何行为或任何其他迹象表明它们是相关的,那么即使是在运行时进行自省的编译器也很难找出正确的事情要做。它无法知道data
指向的BYTE
数组有多大,也无法知道您决定在size
中对其进行编码。
你要求的是所谓的反射-这是:
计算机程序检查的能力并修改结构和行为(特别是值),对象运行时的元数据(属性和函数)。
c++并没有"本地。
我的意思是-已经有一些尝试引入它的某些方面-取得了不同程度的成功-产生了反射的某些方面,但不是"完整的"反射本身,因为你将在Ruby之类的语言中获得。
然而,如果你想冒险,你可以尝试一个名为Reflectabit的反射库:
看看它是否值得(它可能考虑到你的代码),这里引用了它-其中有相当多的如何使用API的例子:
http://www.altdevblogaday.com/2011/09/25/reflection-in-c-part-1-introduction/祝你好运!
c++中通常的模式不是试图找出该类型的成员是什么,而是提供一个操作符,由该类型的实现者实现,能够序列化/反序列化到磁盘。
例如,您可以看一下boost::serialize库。用法不是太复杂,你只需要提供一个函数,按某种顺序列出你的成员,然后库将从那里获得它,并实现不同格式的序列化。- 根据用户回答声明"Players"。用户选择玩家数量。播放器是结构体
- 结构体和类的不同大小(),彼此具有相同的字段类型
- 创建提升 - 通用 C 结构的变体类型
- 将字符数组类型转换为结构体(不是类/对象)
- 使用QGLShaderProgram从Qt传递自定义类型(结构体)统一到GLSL
- 在定义充满成员的结构体时,是否为该结构体类型的每个变量创建这些成员?
- 确定结构体是否具有特定类型的成员
- 如何:公开c++数据结构/类型(结构体,枚举)供c#使用
- 将结构体强制转换为QByteArray类型
- 如何声明具有other类型成员的两个结构体
- 如何在c++中连接两个结构体类型变量
- 试图使用指向结构体向量的指针访问结构体类型时出错
- 从结构体(类的类型)中获取值
- c++模板:我可以/如何使用结构体作为模板的实例化类型
- 用多种类型从c++文件中读取结构体
- 将POD结构体强制转换为派生类型
- 如何在C/ c++中通读结构体的类型
- Boost Fusion:将适应的结构体类型转换为文本
- 使用指针成员对结构体进行类型转换
- 区分具有类型特征的结构体