【发布时间】:2012-04-16 14:08:32
【问题描述】:
假设我们有一个枚举类型:
enum DataType { INT, DOUBLE };
还有一个类型映射器:
template<DataType T>
struct TypeTraits {};
template<>
struct TypeTraits<INT> { typedef int T; };
template<>
struct TypeTraits<DOUBLE> { typedef double T; };
还有一些代表操作的模板(不要担心丑陋的 void 指针和类似 C 的类型转换):
struct Operation {
DataType rettype;
Operation(DataType rettype) : rettype(rettype);
virtual void* compute();
};
template<DataType RetType>
class Constant : public Operation {
typedef typename TypeTraits<RetType>::T RType;
RType val;
Constant(RType val) : val(val), Operation(RetType) {};
virtual void* compute(){ return &val; }
};
template<DataType T1, DataType T2, DataType RetType>
class Add : public Operation {
typedef typename TypeTraits<RetType>::T1 T1Type;
typedef typename TypeTraits<RetType>::T2 T2Type;
typedef typename TypeTraits<RetType>::RetType RType;
RType val;
Operation *c1, *c2;
Add(Operation *c1, Operation *c2) : c1(c1), c2(c2), Operation(RetType) {};
virtual void* compute(){
T1Type *a = (T1Type *)c1->compute();
T2Type *b = (T2Type *)c2->compute();
val = *a + *b;
return &val;
}
};
还有一个抽象的树表示:
class AbstractNode {
enum Type { ADD, INT_CONSTANT, DOUBLE_CONSTANT };
Type type;
int intval;
double doubleval;
child1 *AbstractNode;
child2 *AbstractNode;
}
我们正在从输入中读取序列化的抽象树,以便将其转换为操作树,然后 - 计算结果。
我们想写这样的东西:
algebrator(Operation *op){
if(op->type == AbstractNode::INT_CONSTANT)
return new Constant<INT>(op->intval);
else if(op->type == AbstractNode::DOUBLE_CONSTANT)
return new Constant<DOUBLE>(op->doubleval);
else {
Operation *c1 = algebrator(op->child1),
*c2 = algebrator(op->child2);
DataType rettype = add_types_resolver(c1->rettype, c2->rettype);
return new Add<c1->rettype, c2->rettype, rettype>(c1, c2);
}
}
其中add_types_resolver 是根据操作参数类型指定添加操作的返回类型的东西。
我们当然会失败,编译器会打我们的脸。我们不能将变量用作模板变量!这是因为在编译过程中实例化模板所需的所有信息都必须可用!
现在 - 问题。
除了编写大量 if-else 或 switch-case 语句之外,还有其他解决方案吗?我们不能以任何方式要求编译器在编译期间扩展所有情况吗?模板由枚举参数化,因此我们可以保证这样的过程是有限的。
请不要写出“我认为整个例子搞砸了”之类的回复。我只是想知道是否有一种方法可以为模板提供变量,知道它来自一个有限的小集合。
整个事情看起来有点矫枉过正,但我真的很好奇如何在这种不寻常的情况下实例化类。
【问题讨论】:
-
整个例子搞砸了。模板在类型和编译时常量上参数化,而不是在运行时值上。但听起来你已经意识到这一点......
-
您可以使用 int-to-type 习惯用法根据值生成模板的编译时类型,但是这是否是一个好主意完全是另一回事。
-
将动态查找代码分解到程序的一个角落并使其在没有太多噪音的情况下可用并不难。
-
您可以使用
boost::mpl之类的东西让编译器为您生成所有 if/switch 案例。但这并不简单。
标签: c++ templates template-meta-programming