在我的史诗般的追求中,使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;
}
而且这是所有的模板代码,你应该能够将记录嵌套在记录中.