Traits技术初探

概述:
traits
是一种特性萃取技术,它在Generic Programming中被普遍运用,经常被用于使不一样的类型能够用于相同的操做,或者针对不一样类型提供不一样的实现.traits在实现过程当中每每须要用到如下三种C++的基本特性:
enum
typedef
template
 (partial) specialization
其中:
enum
用于将在不一样类型间变化的标示统一成一个,它在C++中经常被用于在类中替代define,你能够称enum为类中的define;
typedef
则用于定义你的模板类支持特性的形式,你的模板类必须以某种形式支持某一特性,不然类型萃取器traits将没法正常工做.看到这里你可能会想,太苛刻了吧?其实否则,不支持某种特性自己也是一种支持的方式(见示例2,咱们定义了两种标示,__xtrue_type__xfalse_type,分别表示对某特性支持和不支持).
template
 (partial) specialization被用于提供针对特定类型的正确的或更合适的版本.
借助以上几种简单技术,咱们能够利用traits提取类中定义的特性,并根据不一样的特性提供不一样的实现.你能够将从特性的定义到萃取,再到traits的实际使用统称为traits技术,但这种定义使得traits显得过于复杂,我更愿意将traits的定义限于特性萃取,由于这种定义使得traits显得更简单,更易于理解,^_^.

举例:
上面提到过,traits可被用于针对不一样类型提供不一样的实现,那么下面就举两个例子来讲明如何实现这一点.
Example 1:
假定咱们须要为某个类设计一个能够对全部类型(包括普通的int/long...,提供了clone方法的复杂类型CComplexObject,及由该类派生的类)进行操做的函数clone,下面,先用OO的方法来考虑一下解决方案.看到前面的条件,最早跳进你脑子里的确定是Interface,pure virtual function等等.对于咱们本身设计的类CComplexObject而言,这不是问题,可是,对于基本数据类型呢?还有那些没有提供clone方法的复杂类型呢?(这时候你可能会想,要是Java该多easy,全部类都默认从Object派生,Object已提供了一个默认的clone方法,可是,要使类真正支持clone,还必须implements Cloneable,因此,一样也不能避免这里遇到的麻烦).
下面是一个可能的解决方案:
ios

template <typename T, bool isClonable>
class XContainer
{
     ...
     void clone(T* pObj)
     {
         if (isClonable)
         {
             pObj->clone();
         }
         else
         {
             //... non-Clonable algorithm ...
         }
     }
};


可是只要你测试一下,这段代码不能经过编译.为何会这样呢?缘由很简单:对于没有实现clone方法的非Clonable类或基本类型,pObj->clone这一句是非法的.
那么怎样解决上面的这个难题呢?上面不能经过编译的代码告诉咱们,要使咱们的代码经过编译,就不能使非Clonable类或基本类型的代码中出现pObj->clone,即咱们须要针对不一样类型提供不一样的实现.为了实现这一点,咱们能够在咱们的模板类中用enum定义一个trait,以标示类是否为Clonable,而后在原模板类内部引入一个traits提取类Traits,经过对该类进行specilizing,以根据不一样的trait提供不一样的实现.具体实现以下:
函数

#include <iostream>
using namespace std;
class CComplexObject // a demo class
{
public
:
     void clone() {
        cout << "in clone" << endl; 
     }
};
// Solving the problem of choosing method to call by inner traits class
template <typename T, bool isClonable>
class XContainer
{
public:
     enum {
         Clonable = isClonable
         };
     void clone(T* pObj)
     {
         Traits<isClonable>().clone(pObj);
     }
     template <bool flag>
     class Traits
     {
     };
     template <>
     class Traits<true>
     {
     public:
         void clone(T* pObj)
         {
             cout << "before cloning Clonable type" << endl;
             pObj->clone();
             cout << "after cloning Clonable type" << endl;
         }
     };
     template <>
     class Traits<false>
     {
     public:
         void clone(T* pObj)
         {
             cout << "cloning non Clonable type" << endl;
         }
     };
};
void main()
{
     int* p1 = 0;
     CComplexObject* p2 = 0;
     XContainer<int, false> n1;
     XContainer<CComplexObject, true> n2;
     n1.clone(p1);
     n2.clone(p2);
}


编译运行一下,上面的程序输出以下的结果:
测试

cloing something non Clonable
before doing something Clonable
in clone
after doing something Clonable

这说明,咱们成功地根据传入的isClonable模板参数为模板实例选择了不一样的操做,在保证接口相同的状况下,为不一样类型提供了不一样的实现.

Example 2:
咱们再对上面的例子进行一些限制,假设咱们的clone操做只涉及基本类型和CComplexObject及其派生类,那么咱们能够进一步给出下面的解法:
spa

#include <iostream>
using namespace std;
struct __xtrue_type { }; // define two mark-type
struct __xfalse_type { };
class CComplexObject // a demo class
{
public:
     virtual void clone() {
        cout << "in clone" << endl; 
      }
};
class CDerivedComplexObject : public CComplexObject // a demo derived class
{
public:
     virtual void clone() {
           cout << "in derived clone" << endl; 
      }
};
// A general edtion of Traits
template <typename T>
struct Traits
{
     typedef __xfalse_type has_clone_method;
     // trait 1: has clone method or not? All types defaultly has no clone method.
};
// Specialized edtion for ComplexObject
template <>
struct Traits<CComplexObject>
{
     typedef __xtrue_type has_clone_method;
};
template <typename T>
class XContainer
{
     template <typename flag>
     class Impl
     {
     };
     template <>
     class Impl <__xtrue_type>
     {
     public:
         void clone(T* pObj)
         {
             pObj->clone();
         }
     };
     template <>
     class Impl <__xfalse_type>
     {
     public:
         void clone(T* pObj)
         {
         }
     };
public:
     void clone(T* pObj)
     {
         Impl<Traits<T>::has_clone_method>().clone(pObj);
     }
};
void main()
{
     int* p1 = 0;
     CComplexObject c2;
     CComplexObject* p2 = &c2;
     CDerivedComplexObject c3;
     CComplexObject* p3 = &c3;
     // you must point to a derived object by a base-class pointer,
     //it's a little problem
     XContainer<int> n1;
     XContainer<CComplexObject> n2;
     XContainer<CComplexObject> n3;
     n1.clone(p1);
     n2.clone(p2);
     n3.clone(p3);
}

如今,全部基本类型以及CComplexObject类系均可以用于XContainer.

设计

相关文章
相关标签/搜索