C++ c++;创建在编译时未知类型的连续数组

C++ c++;创建在编译时未知类型的连续数组,c++,metaprogramming,dynamic-data,C++,Metaprogramming,Dynamic Data,假设我有几个不同的结构定义(事实上,我大约有50个这样的定义): 它们都是POD,但可以包含完全不同的数据 现在,在运行时,我想确定我需要哪种类型的数据,然后创建一个所选类型的数组(或向量),这样所有的数据都在内存中连续地排列 我该怎么做 另外,假设我有一个整数(它包含一些标志),它决定了我需要什么类型的结构。有没有办法将这些结构的类型定义安排到hashmap中,这样我就只能执行以下操作: vector<myTypeHashMap[flagsInt]> myVect; 向量myVe

假设我有几个不同的结构定义(事实上,我大约有50个这样的定义):

它们都是POD,但可以包含完全不同的数据

现在,在运行时,我想确定我需要哪种类型的数据,然后创建一个所选类型的数组(或向量),这样所有的数据都在内存中连续地排列

我该怎么做

另外,假设我有一个整数(它包含一些标志),它决定了我需要什么类型的结构。有没有办法将这些结构的类型定义安排到hashmap中,这样我就只能执行以下操作:

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";
}