让我说我有一些不同的结构定义(事实上,我有50个这样的定义):
struct Type1{
int i;
float f;
};
struct Type2{
bool b1;
bool b2;
double d;
};
它们都是POD,但可以包含完全不同的数据。
现在,在运行时,我想确定我需要的那种类型,然后创建一个这个所选类型的数组(或向量),这样所有的数据都会在内存中熄灭。
我该怎么做?
也 - 假设我有一个整数(它包含一些标志),它决定了我需要的结构类型。有没有什么方法可以将这些结构的类型定义排列成一个哈希映射,这样我就可以只执行以下操作:
vector<myTypeHashMap[flagsInt]> myVect;
我知道这是相当深入的元编程(其中我不知道:)),但也许有办法做到这一点?
感谢
感谢
答案 0 :(得分:1)
你可以使用某种工厂。在谷歌搜索“factory pattern 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();
此代码未经过测试,可能包含错误;)
请注意,此解决方案具有一些虚拟函数调用等开销。但它是可以接受的。
此外,将TypeTraits直接合并到结构中可能是个好主意。这样可以减少打字,减少代码,减少开销。
答案 1 :(得分:0)
你可以使用一个union结构和std :: vector(注意:这是一个老式的c技术,并不适用于50个对象:D)。统一结构可能是这样的:
struct unifier
{
int type;
union
{
struct A;
struct B;
};
};
如果它们的大小差别不是太大,则此方法允许您混合和匹配类型,或者如果您只使用一种类型,则此机制将允许您将内存重用于不同的对象。
答案 2 :(得分:0)
您可以这样做:
void * buffer;
if (a) {
buffer = new Type1[30];
} else {
buffer = new Type2[30];
}
答案 3 :(得分:0)
你想要一个函数来创建一个由类型?
模板化的数组template <typename T>
T* makeArray( int n )
{
return new T[n];
}
...
Type1* arrayoftype1 = makeArray<Type1>( 10 );
delete[] arrayoftype1;
答案 4 :(得分:0)
您可以使用RTTI编写switch语句,以便在运行时根据对象类型做出决定。
您还可以使用特征模式为元素分配元信息:traits。一旦为类型创建了通用特征和/或特殊特征,就可以将std :: vector容器与另一个模板包装在一起,以创建一个有名的内存对象。你必须创建50个特化,所以试着限制自己的一般特征。
我认为完全坚持我的第一个提示会给你更好的里程,因为你不想为你的类型实例化50个通用对象。
答案 5 :(得分:0)
使用像模板这样的编译时工具时,你无法做你想做的事。
您可能需要做的就是自己处理内存。创建一个包含数字(数组中的元素数)和char *
指针的类。鉴于需要T类型的N个结构,并且int size[]
数组给出各种Ts的大小,请使用new char(N * size[T])
分配内存。存储大小,你准备好了。
要访问内存,您可以使用operator[]
,并返回void *
或主结构,如下所述。 (您返回的内容必须在编译时指定,因此您不能使用任何五十多种结构类型。)
此时,您需要具有将原始字节转换为您喜欢的任何字段的函数,反之亦然。这些可以由operator[]
函数调用。对于没有在编译时确定类型的结构,你不能做任何事情,所以你可能想要一个包含很多字段的主结构,所以它可以处理所有的int
,所有的bool
s,所有float
s,所有double
s等所有结构都将具有。您当然需要表格来显示哪些字段有效。
这是一项繁重的工作,我不得不问这是否真的有必要。这真的会给你带来什么有用的东西吗?
答案 6 :(得分:0)
如何选择在运行时使用哪种类型?你没有提到这一点,而且凭借我对C ++的了解,我根本没有看到一种简单的方法。
无论如何,一旦你在运行时选择了你的选择类型,你也可以确定它的大小(使用sizeof
),然后创建一个数组:
size_t const size = sizeof(your_type);
char* buffer = new char[size * count];
your_type* = reinterpret_cast<your_type*>(buffer);
现在,这段代码有效,但完全没用,因为它需要知道类型your_type
,然后你当然可以说new your_type[count]
。但是,您可以使用建议的整数标记创建类型到其大小的映射:
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];
然而,对于实际的解决方案,您应该依靠继承来组成一个类型层次结构,然后可能依赖其他人提到的工厂方法。
PS:由于你想在运行时这个行为,模板元编程实际上与它无关,恰恰相反:元编程在编译时执行
答案 7 :(得分:0)
为什么你需要它们在记忆中连续?
我怀疑你最好只创建一个指针数组,然后动态地在运行时分配类。然后,您可以设置数组中的指针以指向您创建的内容。
创建类 - 为什么使用结构而不是类?我只想为你想要的所有类型创建一个超类,为每个不同类型创建一个子类,一个指向对象的指针的数组(或列表或集合),你可以在运行时创建它们。
结构指针解决方案 - 如果必须使用结构,则可以创建一个结构,该结构具有标记(用于标识类型)和指向不同结构的指针的并集。这将是类型安全的访问,不需要强制转换,标记将有助于防止代码错误。这将提高内存效率,就像您创建实际结构的并集一样,您必须为最大的结构分配内存。
结构解决方案 - 如果你确实需要它在内存中连续,那么创建一个带有标签id和你想要的不同结构的联合的结构。
理想情况下,您将拥有所有不同类型的超类,然后
答案 8 :(得分:0)
试着充实drspod上面的答案,假设你做了以下帮助类:
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]); }
}
现在你有一个从整数(或标志或其他)到HelperBase
的映射:
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);
答案 9 :(得分:0)
在我看来,你最好走C路而不是C ++路线。
这就是我如何在不了解具体领域的情况下解决您的问题的方法:
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.
我并不特别知道你要完成什么,所以这可能有点难以适应。无论如何,50种类型意味着很多代码,无论你做什么。
答案 10 :(得分:0)
根据您声明的要求,您需要一个 Factory 来创建您想要的对象。 Factory 可以像std::map<*struct name*, *pointer to creation function*>
一样简单。但是,您还需要某种对象,其中包含可在运行时在神秘对象上执行的操作(这是另一个主题)。
为了使 Factory 工作,您需要拥有从公共基类派生的所有对象,或者使用void *
指针来引用它们。 (在这里看起来像泛型编程技术......)
大多数 Factory 设计模式返回指向神秘对象的指针。它返回一个指向基类实例的指针;但你所知道的是它遵循基类中定义的接口,因此它是一个神秘的对象。 oracle说你需要知道工厂生成的对象类型,以便对对象执行特殊操作。您的大多数计划都是if object is *this* type, perform *special action*
。
正如Neil所说,这是重新设计的地方。将视角更改为Object的观点。对象决定了一切。因此,这些方法应属于对象,使其自给自足。例如,一旦 Factory 创建了一个对象,该对象将读入其数据并显示注释和结果。如果calculate
方法对所有对象都是通用的,那么它就成为基类的纯虚方法,迫使所有后代都有一个实现。好的部分是你可以迭代一个指向基类的指针数组并执行这个calculate
方法,而不需要知道实际的实现。
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";
}
答案 11 :(得分:0)
听起来Boost.Any可能具有潜在用途,至少可以了解如何满足您的需求。