首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Enum变量作为动态模板参数

Enum变量作为动态模板参数
EN

Stack Overflow用户
提问于 2012-04-02 22:04:24
回答 2查看 9.2K关注 0票数 3

让我们假设,我们有一个被激活的类型:

代码语言:javascript
复制
enum DataType { INT, DOUBLE };

和一种类型的地图:

代码语言:javascript
复制
template<DataType T>
struct TypeTraits {}; 

template<>
struct TypeTraits<INT> { typedef int T; };

template<>
struct TypeTraits<DOUBLE> { typedef double T; };

还有一些表示操作的模板(不要为丑陋的空指针和类似于C的类型转换而烦恼):

代码语言:javascript
复制
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;
  }   
};  

和抽象树表示:

代码语言:javascript
复制
class AbstractNode {
  enum Type { ADD, INT_CONSTANT, DOUBLE_CONSTANT };

  Type type;
  int intval;
  double doubleval;
  child1 *AbstractNode;
  child2 *AbstractNode;
}

我们从输入中读取序列化的抽象树,以便将其转换为操作树,然后-计算结果。

我们想写这样的东西:

代码语言:javascript
复制
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语句之外,还有其他解决方案吗?我们不能要求编译器在编译过程中扩展所有的情况吗?模板是参数化的枚举,所以我们有一个保证,这样的过程是有限的。

请不要写像“我认为整个例子都搞砸了”这样的回答。我只想知道是否有一种方法可以用变量填充模板,知道它来自一个有限的、小的集合。

整件事看上去可能有点过火,但我真的很好奇,在这种不寻常的情况下,如何实例化类。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-04-06 10:27:41

使用宏的快速‘n’脏解决方案:

column_type.cc:

代码语言:javascript
复制
enum ColumnType {
  INT = 1,
  DOUBLE = 2,
  BOOL = 3
};

typed_call_test.cc (使用示例):

代码语言:javascript
复制
#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 (“库”):

代码语言:javascript
复制
// 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++模板问题:)

第二副:下面是我的同类类型的样子:

代码语言:javascript
复制
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;
};
票数 2
EN

Stack Overflow用户

发布于 2012-04-02 22:15:17

不能要求编译器在编译过程中扩展所有的情况吗?

你可以做到这一点。介绍动态的条件->TMP。如果你在正确的地方这样做,那么你就没有什么条件可以写了。引入类型和常量作为编译时信息将有助于最小化这一点。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9984491

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档