C++ c++;创建在编译时未知类型的连续数组
假设我有几个不同的结构定义(事实上,我大约有50个这样的定义): 它们都是POD,但可以包含完全不同的数据 现在,在运行时,我想确定我需要哪种类型的数据,然后创建一个所选类型的数组(或向量),这样所有的数据都在内存中连续地排列 我该怎么做 另外,假设我有一个整数(它包含一些标志),它决定了我需要什么类型的结构。有没有办法将这些结构的类型定义安排到hashmap中,这样我就只能执行以下操作:C++ c++;创建在编译时未知类型的连续数组,c++,metaprogramming,dynamic-data,C++,Metaprogramming,Dynamic Data,假设我有几个不同的结构定义(事实上,我大约有50个这样的定义): 它们都是POD,但可以包含完全不同的数据 现在,在运行时,我想确定我需要哪种类型的数据,然后创建一个所选类型的数组(或向量),这样所有的数据都在内存中连续地排列 我该怎么做 另外,假设我有一个整数(它包含一些标志),它决定了我需要什么类型的结构。有没有办法将这些结构的类型定义安排到hashmap中,这样我就只能执行以下操作: vector<myTypeHashMap[flagsInt]> myVect; 向量myVe
vector<myTypeHashMap[flagsInt]> myVect;
向量myVect;
?
我知道这相当于彻底的元编程(我不知道:),但也许有办法做到这一点
谢谢
谢谢您可以使用union struct和std::vector(注意:这是一种老式的c技术,并不适用于50个对象:D)。统一结构可以如下所示:
struct unifier
{
int type;
union
{
struct A;
struct B;
};
};
void * buffer;
if (a) {
buffer = new Type1[30];
} else {
buffer = new Type2[30];
}
如果它们的大小差异不太大,则此方法允许您混合和匹配类型,或者如果仅使用一种类型,则此机制将允许您为不同的对象重用内存 您可以这样做:
struct unifier
{
int type;
union
{
struct A;
struct B;
};
};
void * buffer;
if (a) {
buffer = new Type1[30];
} else {
buffer = new Type2[30];
}
您想要一个函数来创建一个按类型模板化的数组吗
template <typename T>
T* makeArray( int n )
{
return new T[n];
}
...
Type1* arrayoftype1 = makeArray<Type1>( 10 );
delete[] arrayoftype1;
模板
T*makeArray(整数n)
{
返回新的T[n];
}
...
Type1*arrayoftype1=makeArray(10);
删除[]arrayoftype1;
您可以使用编写switch语句,以在运行时根据对象的类型做出决策
您还可以使用trait模式为您的类型分配元信息:。一旦为类型创建了泛型特征和/或专用特征,就可以用另一个模板包装std::vector容器来创建连续内存对象。你将不得不创建50个专门化,所以试着把自己限制在一个通用特性上
我认为完全坚持我的第一条建议会让你有更好的效果,因为你不想为你的类型实例化50个泛型对象。你可以使用某种工厂。在谷歌上搜索“工厂模式c++” 一些简单的示例代码来解释它:
enum TypeCode { FOO, BAR, ... };
void* makeInstance( TypeCode t ) {
switch( t ) {
case FOO: return new FooStruct;
case BAR: return new BarStruct;
...
}
}
void* makeArray( TypeCode t, size_t len ) {
switch( t ) {
case FOO: return new FooStruct[len];
case BAR: return new BarStruct[len];
...
}
}
编辑TypeCode
到某些功能和类型描述的OOP样式映射示例:
// base class .. you may add common functionality
class TypeTraitBase {
public:
virtual void* newStruct() const = 0;
virtual void* newArray( size_t len ) const = 0;
virtual size_t getSize() const = 0;
virtual TypeCode getCode() const = 0;
// add whatever else you need.. e.g.
virtual bool isNumeric() const { return false; }
};
template <TypeCode TCode, typename TStruct>
class TypeTrait : public TypeTraitBase {
public:
virtual TStruct* newStruct() const { return new TStruct; }
virtual TStruct* newArray( size_t len ) const { return new TStruct[len]; }
virtual size_t getSize() const { return sizeof(TStruct); }
virtual TypeCode getCode() const { return TCode; }
};
/* OPTIONAL...
// you may add specializations for some types
// - though it is required only if you want something like isNumeric(),
// - newStruct, newArray and so on do not require specializations!
template < INTEGER, IntegerStruct >
class TypeTrait : public TypeTraitBase {
public:
virtual TStruct* newStruct() const { return new IntegerStruct; }
virtual TStruct* newArray( size_t len ) const { return new IntegerStruct[len]; }
virtual size_t getSize() const { return sizeof(IntegerStruct); }
virtual TypeCode getCode() const { return INTEGER; }
virtual bool isNumeric() const { return true; }
};
*/
class TypeTraitMgr {
static std::map<TypeCode,TypeTraitBase*> traits;
public:
static void reg( TypeTraitBase* tt ) { traits[tt->getCode()] = tt; }
static void cleanup() { /* delete all TypeTraits in traits */ }
static TypeTraitBase* get( TypeCode code ) { return traits[code]; }
};
// in .cpp file: instantiate the static member:
std::map<TypeCode,TypeTraitBase*> traits;
// somewhere before you use it, register all known types:
TypeTraitMgr::reg( new TypeTrait<FOO,YourFOOStruct> );
TypeTraitMgr::reg( new TypeTrait<BAR,YourBARStruct> );
// use it...
void* foo = TypeTraitMgr::get( FOO )->newStruct();
size_t size_of_foo = TypeTraitMgr::get( FOO )->getSize();
// on shutdown, cleanup type traits (they were allocated on heap, delete required)
TypeTraitMgr::cleanup();
//基类。。您可以添加通用功能
类类型跟踪数据库{
公众:
虚拟void*newStruct()常量=0;
虚拟void*newArray(size\t len)const=0;
虚拟大小\u t getSize()常量=0;
虚拟类型代码getCode()常量=0;
//加上你需要的任何东西。
虚拟bool isNumeric()常量{return false;}
};
模板
类TypeTrait:publictypetraitbase{
公众:
virtual TStruct*newStruct()常量{return new TStruct;}
virtual TStruct*newArray(size_t len)const{return new TStruct[len];}
虚拟大小_t getSize()常量{return sizeof(TStruct);}
虚拟类型代码getCode()常量{return TCode;}
};
/*可选的。。。
//您可以为某些类型添加专门化
//-尽管只有在需要类似isNumeric()的内容时才需要它,
//-newStruct、newArray等不需要专门化!
模板<整数,整数结构>
类TypeTrait:publictypetraitbase{
公众:
virtual TStruct*newStruct()常量{return new IntegerStruct;}
虚拟结构*newArray(size_t len)常量{返回新的整数结构[len];}
虚拟大小_t getSize()常量{return sizeof(IntegerStruct);}
虚拟类型代码getCode()常量{返回整数;}
虚拟bool isNumeric()常量{return true;}
};
*/
类TypeTraitMgr{
静态std::图谱特征;
公众:
静态void reg(TypeTraitBase*tt){traits[tt->getCode()]=tt;}
静态void cleanup(){/*删除traits*/}中的所有TypeTraits
静态TypeTraitBase*get(TypeCode代码){returntraits[code];}
};
//在.cpp文件中:实例化静态成员:
地图性状;
//在使用之前,请先注册所有已知类型:
TypeTraitMgr::reg(新的TypeTrait);
TypeTraitMgr::reg(新的TypeTrait);
//使用它。。。
void*foo=TypeTraitMgr::get(foo)->newStruct();
size\u t size\u of\u foo=TypeTraitMgr::get(foo)->getSize();
//关闭时,清除类型特征(它们是在堆上分配的,需要删除)
TypeTraitMgr::cleanup();
此代码未经测试,可能包含错误;)
请注意,此解决方案有一些虚拟函数调用等开销。但这是可以接受的
另外,将typetrait直接合并到结构中可能是一个好主意。这将导致更少的键入、更少的代码和更少的开销。在使用编译时工具(如模板)时,您将无法执行您想要的操作 你可能要做的是自己处理内存。创建一个包含数字(数组中的元素数)和
char*
指针的类。如果需要类型为T的N个结构,以及提供各种T的大小的int size[]
数组,请使用new char(N*size[T])
分配内存。储存好尺寸,你就可以出发了
要访问内存,您可以使用操作符[]
,并返回void*
,或如下所述的主结构。(返回的内容必须在编译时指定,因此不能使用50多种结构类型中的任何一种。)
在这一点上,您需要有一个函数,可以将原始字节转换为您喜欢的任何字段,反之亦然。这些可以由操作符[]
函数调用。对于编译时没有确定类型的结构,您无法执行任何操作,因此您可能需要一个包含大量字段的主结构,这样它就可以处理所有的int
s、所有的bool
s、所有的float
s、所有的double
s等等您的结构。当然,您需要表格来显示哪些字段是val
enum type { tfoo, tbar };
std::map<type, size_t> type_sizes;
type_sizes[tfoo] = sizeof(foo);
type_sizes[tbar] = sizeof(bar);
// …
char* buffer = new char[type_sizes[type_index] * count];
class HelperBase {
virtual void *MakeArray(int n) = 0;
virtual void *Get(void *array, int i) = 0;
}
template <typename T> class Helper {
void *MakeArray(int n) { return new T[n]; }
void *Get(void *array, int i) { return &(((T*)array)[i]); }
}
std::map<int, HelperBase*> GlobalMap;
GlobalMap[1] = new HelperBase<Type1>;
GlobalMap[2] = new HelperBase<Type2>;
// Don't forget to eventually delete these (or use smart pointers)
void *array = GlobalMap[someIndex].MakeArray(n);
void *thirdElement = GlobalMap[someIndex].Get(2);
void *out_buf;
write_type(struct &a)
{
out_buf = malloc(sizeof(a));
memcpy(out_buf, a, sizeof(a));
}
write_type(struct &b); //so forth and so on.
struct CommonBase
{
virtual ResultType calculate(void) = 0;
};
struct Type1 : CommonBase
{
int i;
float f;
ResultType calculate(void); // performs calculation using *i* and *f*
};
struct Type2{
bool b1;
bool b2;
double d;
ResultType calculate(void); // performs calculation using *b1*, *b2* and *d*
};
//...
std::vector<CommonBase *> the_objects;
//...
std::vector<CommonBase *>::iterator iter;
for (iter = the_objects.begin();
iter != the_objects.end();
++iter)
{
ResultType result;
result = (*iter)->calculate();
std::cout << "Result: " << result << "\n";
}