类型和值之间的映射(Int2Type)

       在C++中,术语“转化”(conversion)描述的是从另外一个类型的值(value)获取一个类型(type)的值的过程。可是有时候你会需要一种不同类型的转化:可能是在你有一个类型时需要获取一个值,或是其它的类似情形。在C++中做这样的转化是不寻常的,因为类型域和值域之间隔有有一堵很严格的界线。可是,在一些特定的场合,你需要跨越这两个边界,本栏就是要讨论该怎么做到这个跨越。

映射整数为类型

一个对许多的generic programming编程风格非常有帮助的暴简单的模板:

template <int v>
struct Int2Type
{
    enum { value = v };
};

对传递的每一个不同的常整型值,Int2Type“产生”一个不同的类型。这是因为不同的模板的实体(instantiation)是不同的类型,所以Int2Type<0>不同于Int2Type<1>等其它的类型的。此外,产生类型的值被“存放”在枚举(enum)的成员值里面。

不管在任何时候,只要你需要快速“类型化”(typify)一个整型常数时,你都可以使用Int2Type。

 

问题描述:
当需要根据不同的值选择不同的行为时,普通的做法是利用if...else...或者case结构
来实现分支选择。在一个型别模板化的函数过程中,则可能出现问题。
看下面的第一部分:

 Part 1 
如下的范型容器NiftyContainer的元素型别范型化为T。在容器中需要实现元素的赋值行为。非常规的自定义类型,其复制行为是复杂的。 特别是具有多态特性的类型和普通的类型,其复制过程不一样。例如,普通类型可以采用逐位复制的简单方式,而具有多态特性(例如含有指针成员)的类对象则不宜采用 这种方式。此处假定普通类型的复制采用拷贝构造函数方式而多态的类型则采用一个专门的虚函数clone来做拷贝。

  1. #include <cstdlib>
  2. using namespace std;
  3. class Normal {
  4.     int _i;
  5. public:
  6.     Normal() { _i = 0; }
  7.     Normal(const Normal& nml) { _i = nml._i; }
  8.     // other members omitted
  9. };
  10. class Polym {
  11.     int *_pi;
  12.     Polym(const Polym&);                    // forbids copy-constructor
  13.     void setp(int* i) { _pi = i; }
  14. public:
  15.     Polym() { _pi = 0; }
  16.     Polym* clone();
  17.     // other members omitted
  18. };
  19. template<class T, bool isPolymorphic> 
  20. class NiftyContainer
  21. {
  22.    // other members omitted
  23. public:
  24.    void DoSomething()
  25.     {
  26.        T* pSomeObj =new T;
  27.       if (isPolymorphic)                          // branch1 
  28.        {
  29.            T* pNewObj = pSomeObj->clone();   // customized behavior for copying
  30.             // some operations on polymorphic object
  31.             pNewObj = 0;
  32.        }
  33.        else                                     // branch2
  34.         {
  35.            T* pNewObj = new T(*pSomeObj);  // using copy-constructor
  36.            // some operations on non-polymorphic object
  37.           delete pNewObj;
  38.         }
  39.        delete pSomeObj;
  40.     }
  41.    // other members omitted
  42. };
  43. int main(int argc, char* argv[])
  44. {
  45.     // using the container with elements' type Normal
  46.    NiftyContainer<Normal, false> nc;
  47.    nc.DoSomething(); // error: 类Normal没有成员函数clone 
  48.     
  49.    // using the container with elements' type Polym
  50.     NiftyContainer<Polym, true> nc2; //error: 类Polym的copy-constructor private 
  51.    nc2.DoSomething();
  52.     
  53.    system("PAUSE");
  54.    return EXIT_SUCCESS;
  55. }

错误解析
按照我们的预期,如果元素类型是多态的,那么只执行branch1部分,否则只执行branch2,因为两种类型的元素有不同的拷贝函数。但是编译器可不会理会这些,一律的都要加以编译,因此出错了。

 

对于模板来说,不同的参数意味着不同的类型。 此外,模板的编译有一个特性,即没有用到的模板函数是不会参与到编译中的,只进行语法正确性的分析。 函数可以根据参数进行重载。

 

为了做到“根据常数的值(此处就是isPolymorphic)只编译其中某一个分支(例如branch1),而不编译其它分支,从而保证最后的代码中只包含需要的代码”, 我们可以利用上述的模板编译特性和函数重载特性。

  1. template<int v>
  2. struct Int2Type {       // 创造了这个模板是为了用不同的常数值产生不同的类型 
  3.     enum {value=v};
  4. };
  5. template<class T, bool isPolymorphic>
  6. class NiftyContainer
  7. {
  8. private:
  9.     void DoSomething(T* pObj, Int2Type<true>) // function_p 
  10.     {
  11.         T* pNewObj = pObj->Clone();
  12.         // some operations on polymorphic object
  13.         pNewObj = 0;
  14.     }
  15.     void DoSomething(T* pObj, Int2Type<false>) // function_n
  16.     {
  17.         T* pNewObj = new T(*pObj);
  18.         // some operations on non-polymorphic object
  19.     }
  20. public:
  21.     void DoSomething(T* pObj)
  22.     {
  23.         DoSomething(pObj, Int2Type<isPolymorphic>());
  24.     }
  25.     // other members are omitted
  26. };
  27. int main(int argc, char* argv[])
  28. {
  29.     // using the container with elements' type Normal
  30.     NiftyContainer<Normal, false> nc;// ok
  31.     
  32.     // using the container with elements' type Polym
  33.     NiftyContainer<Polym, true> nc2; // ok
  34.     
  35.     system("PAUSE");
  36.     return EXIT_SUCCESS;
  37. }

在编译过程中,根据传递的isPolymorphic模板参数值的不同,编译器将选择实现哪个函数。 若为true,则实现function_p,而不会尝试去编译function_n。 这样就成功做到了编译期多态,而不是执行期多态。
这个技术的关键点就在于Int2Type模板。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值