让我们假设,我们有一个被激活的类型:
enum DataType { INT, DOUBLE };和一种类型的地图:
template<DataType T>
struct TypeTraits {};
template<>
struct TypeTraits<INT> { typedef int T; };
template<>
struct TypeTraits<DOUBLE> { typedef double T; };还有一些表示操作的模板(不要为丑陋的空指针和类似于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-否则或开关-case语句之外,还有其他解决方案吗?我们不能要求编译器在编译过程中扩展所有的情况吗?模板是参数化的枚举,所以我们有一个保证,这样的过程是有限的。
请不要写像“我认为整个例子都搞砸了”这样的回答。我只想知道是否有一种方法可以用变量填充模板,知道它来自一个有限的、小的集合。
整件事看上去可能有点过火,但我真的很好奇,在这种不寻常的情况下,如何实例化类。
发布于 2012-04-06 10:27:41
使用宏的快速‘n’脏解决方案:
column_type.cc:
enum ColumnType {
INT = 1,
DOUBLE = 2,
BOOL = 3
};typed_call_test.cc (使用示例):
#include <iostream>
#include "column_type.cc"
#include "typed_call.cc"
template <ColumnType T>
void PrintType() {
::std::cout << T <<::std::endl;
}
int main() {
ColumnType type = INT;
// this won't compile:
// PrintType<type>();
// and instead of writing this:
switch (type) {
case INT:
PrintType<INT>();
break;
case DOUBLE:
PrintType<DOUBLE>();
break;
case BOOL:
PrintType<BOOL>();
break;
}
// now you can write this:
TYPED_CALL(PrintType, type, );
return 0;
}typed_call.cc (“库”):
// Requirements:
// |function| return type must be void
//
// Usage:
//
// having for instance such |type| variable:
// ColumnType type = INT;
// and such |foo| function definition:
// template <ColumnType T>
// void foo(t1 arg1, t2 arg2) {
// …
// }
//
// instead of writing (won't compile):
// foo<type>(arg1, arg2);
// write this:
// TYPED_CALL(foo, type, arg1, arg2);
//
//
// for foo with 0 arguments write this:
// TYPED_CALL(foo, type, );
//
#define TYPED_CALL(function, type, args...) { \
switch (type) { \
case INT: \
function<INT>(args); \
break; \
case DOUBLE: \
function<DOUBLE>(args); \
break; \
case BOOL: \
function<BOOL>(args); \
break; \
} \
}
#define BASE_TYPED_CALL(function, type, args...) { \
switch (type) { \
case INT: \
function<int>(args); \
break; \
case DOUBLE: \
function<double>(args); \
break; \
case BOOL: \
function<bool>(args); \
break; \
} \
}要将此解决方案“升级”,您可以用一个函数(仍然包含类似的开关结构)替换宏。但是,您可能希望传递一个函子(带有()运算符的对象)作为这个函数的参数,而不是像这个宏中那样的普通函数。顺便说一句:他们在谷歌就是这样做的。
第一位同学:你好,华沙大学柱状和分布式DataWarehouses课程的同学!本课程正在产生许多令人费解的C++模板问题:)
第二副:下面是我的同类类型的样子:
template <ColumnType T>
struct EnumToBuiltin {
};
template <>
struct EnumToBuiltin<INT> {
typedef int type;
};
template <>
struct EnumToBuiltin<DOUBLE> {
typedef double type;
};
template <>
struct EnumToBuiltin<BOOL> {
typedef bool type;
};
template <typename T>
struct BuiltinToEnum {
};
template <>
struct BuiltinToEnum<int> {
static const ColumnType type = INT;
};
template <>
struct BuiltinToEnum<double> {
static const ColumnType type = DOUBLE;
};
template <>
struct BuiltinToEnum<bool> {
static const ColumnType type = BOOL;
};发布于 2012-04-02 22:15:17
不能要求编译器在编译过程中扩展所有的情况吗?
你可以做到这一点。介绍动态的条件->TMP。如果你在正确的地方这样做,那么你就没有什么条件可以写了。引入类型和常量作为编译时信息将有助于最小化这一点。
https://stackoverflow.com/questions/9984491
复制相似问题