我正在使用C++(vc2008)读取/写入结构,其类型在运行时明显根据ID标志更改。创建正确的类型和/或读写需要一个开关。现有的最接近的例子是Using template instead of switch,但这不允许在运行时指定类型。为了避免在多个地方创建相同的交换机,我一直在研究使用递归模板来解决这个问题。这是我第一次使用这些代码,因此可能会对代码示例做一些重大改进!递归模板列表,而不是使用基于键/ ID的搜索的硬编码switch语句
下面是一个工作示例。正如你将在'main()'中看到的那样,所使用的类型id是一个变量int,它可以被设置为任何运行时值。在类型列表<>上调用一个函数将遍历这些类型,直到它达到一个匹配的ID或一个空类型。
#include <stdio.h>
#include <iostream>
//Base type
struct Base
{
//NOTE: The virtual destructor can be added to aid with debugging
//virtual ~Base(){}
friend std::ostream& operator << (std::ostream& stream, const Base& rhs)
{ return stream << "Base"; }
};
struct A : Base
{
friend std::ostream& operator << (std::ostream& stream, const A& rhs)
{ return stream << "A"; }
};
struct B : Base
{
friend std::ostream& operator << (std::ostream& stream, const B& rhs)
{ return stream << "B"; }
};
struct C : Base
{
friend std::ostream& operator << (std::ostream& stream, const C& rhs)
{ return stream << "C"; }
};
//Recursive template type
// - If the ID/key does not match the next type is checked and so on
template < unsigned int kID, typename _Type, typename _TNext >
struct TypeList
{
typedef _Type Type;
typedef typename _TNext::Base Base;
static Base* doNew(unsigned int id)
{ return id == kID ? new _Type() : (Base*)_TNext::doNew(id); }
static void doDelete(unsigned int id, Base* rhs)
{ id == kID ? delete (_Type*)rhs : _TNext::doDelete(id, rhs); }
static std::ostream& doWrite(unsigned int id, std::ostream& stream, const Base* rhs)
{ return id == kID ? stream << (*(const _Type*)rhs) : _TNext::doWrite(id, stream, rhs); }
};
//Specialise the 'void' case to terminate the list
// TODO; this doesn't seem as elegant as possible!? How can we separate the logic from the functionality better...
template < unsigned int kID, typename _Type >
struct TypeList<kID, _Type, void>
{
typedef _Type Type;
typedef _Type Base;
static _Type* doNew(unsigned int id)
{ return id == kID ? new _Type() :0; }
static void doDelete(unsigned int id, _Type* rhs)
{ if (id == kID) delete rhs; }
static std::ostream& doWrite(unsigned int id, std::ostream& stream, const _Type* rhs)
{ return id == kID ? stream << (*(const _Type*)rhs) : stream; }
};
// ID values used to identify the different structure types
enum eID
{
ID_A,
ID_B,
ID_C,
};
//Create our ID and Type list
typedef TypeList< ID_A, A,
TypeList< ID_B, B,
TypeList< ID_C, C,
TypeList< -1 , Base, void> > > > TypesList;
int _tmain(int argc, _TCHAR* argv[])
{
eID type = ID_C; //, We are dealing with a type of 'C'
Base* newInst = TypesList::doNew(type); //Create a new C
TypesList::doWrite(type, std::cout, newInst); //Write 'C' to the console
TypesList::doDelete(type, newInst); //Delete C
return 0;
}
什么是人们对这个和其他更好的方式做什么的意见?主要有一种方法可以很好地将逻辑从类的功能中分离出来,以便在TypeList < ,, _ Type>和TypeList < ,, void>实例化中保存重复的代码。
编辑:该解决方案最好不需要运行时设置'添加'类型查找或喜欢。
欢呼声中,克雷格
你确定这是对的吗?如果你有一个没有基础的相互依赖的类,类型列表是很好的。对于您的案例工厂(基于具有这种类型和基础的模板参数的地图)是最佳选择。 – Torsten 2012-08-16 08:05:37
我不能有任何工厂对象的运行时设置,并且已知类型的数量。如果有更好的方法来实现这一点,我将非常感激,我不确定如何在不增加复杂性的情况下使用工厂,也不需要编译时间。 – Crog 2012-08-16 08:29:54