在我的史诗般的追求中,使C做事情不应该,我试图把一个编译时生成的类放在一起.
基于预处理器定义,如(粗略概念)
CLASS_BEGIN(Name) RECORD(xyz) RECORD(abc) RECORD_GROUP(GroupName) RECORD_GROUP_RECORD(foo) RECORD_GROUP_RECORD(bar) END_RECORDGROUP END_CLASS
虽然我相当确定我生成一个类,使用这种结构从文件系统读取数据(也许甚至使用模板元编程),我看不到如何生成两个函数来访问数据,功能读取数据.
我想要结束一个这样的类
class Name{ public: xyz_type getxyz(); void setxyz(xyz_type v); //etc list<group_type> getGroupName(); //etc void readData(filesystem){ //read xyz //read abc //etc } };
有人有任何想法,如果这是可能的吗?
– 编辑 –
澄清这个的预期用途.我有一个标准格式的文件我想要阅读.格式已经被定义了,所以它不是可以改变的.每个文件可以包含任何数字记录,每个记录可以包含任何数量的子记录.
许多记录类型每个都包含一组不同的子记录,但它们可以被定义.因此,例如Heightmap记录必须包含一个Heightmap,但可以包含法线.
所以我想要这样定义一个记录:
CLASS_BEGIN(Heightmap) RECORD(VHDT,Heightmap,std::string) //Subrecord Name,Readable Name,Type RECORD_OPTIONAL(VNML,Normals,std::string) END_CLASS
class Heightmap{ public: std::string getHeightmap(){ return mHeightmap->get<std::string>(); } void setHeightmap(std::string v){ mHeight->set<std::string>(v); } bool hasNormal(){ return mNormal != 0; } //getter and setter functions for normals go here private: void read(Record* r){ mHeightmap = r->getFirst(VHDT); mNormal = r->getFirst(VNML); } SubRecord* mHeightmap,mNormal; }
我遇到的问题是我需要每次预处理定义两次.一次用于在类中定义函数定义,一次用于创建读取函数.由于预处理器是纯功能的,我无法将数据推送到队列,并在END_CLASS marco定义上生成类.
我看不出有关这个问题的方法,但是想知道有没有更了解C的人.
解决方法
您可能可以使用boost
tuples来解决这个问题.它将导致与现在想到的不同的设计,但它应该允许您以通用的方式解决问题.
以下示例定义了“std :: string,bool”形式的记录,然后从流中读取该数据.
#include "boost/tuple/tuple.hpp" #include <iostream> #include <sstream> using namespace ::boost::tuples;
这些功能用于从istream读取数据.我们达到最后一个记录类型后,第一个重载通过元组停止迭代:
// // This is needed to stop when we have no more fields void read_tuple (std::istream & is,boost::tuples::null_type ) { } template <typename TupleType> void read_tuple (std::istream & is,TupleType & tuple) { is >> tuple.template get_head (); read_tuple (is,tuple.template get_tail ()); }
以下类实现了我们的记录的getter成员.使用RecordKind作为我们的关键,我们得到我们感兴趣的具体成员.
template <typename TupleType> class Record { private: TupleType m_tuple; public: // // For a given member - get the value template <unsigned int MBR> typename element <MBR,TupleType>::type & getMember () { return m_tuple.template get<MBR> (); } friend std::istream & operator>> (std::istream & is,Record<TupleType> & record) { read_tuple (is,record.m_tuple); } };
下一个类型是我们记录的元描述.枚举给我们一个象征性的名字,我们可以用来访问成员,即.字段名称.元组然后定义了这些字段的类型:
struct HeightMap { enum RecordKind { VHDT,VNML }; typedef boost::tuple < std::string,bool > TupleType; };
最后,我们构建一个记录,并从流中读取一些数据:
int main () { Record<HeightMap::TupleType> heightMap; std::istringstream iss ( "Hello 1" ); iss >> heightMap; std::string s = heightMap.getMember < HeightMap::VHDT > (); std::cout << "Value of s: " << s << std::endl; bool b = heightMap.getMember < HeightMap::VNML > (); std::cout << "Value of b: " << b << std::endl; }
而且这是所有的模板代码,你应该能够将记录嵌套在记录中.