要想深入的理解STL的迭代器、分配器等,就必须了解C++模板编程中的一个技巧——Traits。
1、问题的提出
C++的模板特性为泛型编程提供了支持。这样我们就可以编写更加通用的代码,而不必过分去关心参数的类型。然而事实却是,类型的不同,很多时候却影响到了算法中的某个小小的实现。举个标准库里的类string,wstring。
其实它们对应的是两个模板,前者单字符,后者宽字符。
typedef basic_string<char, char_traits<char>, allocator<char> > string; typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstring;</span>
模板basic_string需要有一个得出字符串长度的函数length,那么问题就来了。因为char和wchar_t所对应的求长度API并不一样。前者是strlen,后者是wcslen。
正是为了解决这样类似的问题,C++中的traits技巧被提炼出来了。
2、解决方法
因为模板参数的类型不同,可能会影响到模板中具体的算法,那么我们就需要把这些与模板参数相差的方法从模板basic_string中提取出来,而保证basic_string算法的一致不受参数类型不同的影响。而上面的char_traits模板即是把与模板参数相差的方法都封装起来了。如果定义这样一个模板.
template<class _Elem>
struct char_traits
{
static void __CLRCALL_OR_CDECL assign(_Elem& _Left, const _Elem& _Right)
{        // assign an element
_Left = _Right;
}
static bool __CLRCALL_OR_CDECL eq(const _Elem& _Left, const _Elem& _Right)
{        // test for element equality
return (_Left == _Right);
}
//……
//……
//…..
static size_t __CLRCALL_OR_CDECL length(const _Elem *_First)
{        // find length of null-terminated sequence
//                _DEBUG_POINTER(_First);
size_t _Count;
for (_Count = 0; !eq(*_First, _Elem()); ++_First)
++_Count;
return (_Count);
}
};</span>
这里的legnth实现是一个通用算法循环遍历,并没有使用系统的strlen,wcslen,效率相对低一些。那么如果我一定要使用strlen,wcslen呢?
这里就需要用到模板的特化,也即指定模板的参数类型。
// STRUCT char_traits<wchar_t>
    template<> struct  char_traits<wchar_t>
          {    // properties of a string or stream wchar_t element
    static void __CLRCALL_OR_CDECL assign(_Elem& _Left, const _Elem& _Right)
        {    // assign an element
        _Left = _Right;
        }
    static bool __CLRCALL_OR_CDECL eq(const _Elem& _Left, const _Elem& _Right)
        {    // test for element equality
        return (_Left == _Right);
        }
        ……
        ……
        …..
    static size_t __CLRCALL_OR_CDECL length(const _Elem *_First)
        {    // find length of null-terminated sequence
    //        _DEBUG_POINTER(_First);
        return (::wcslen(_First));
        }
    };
    
        // STRUCT char_traits<char>
    template<> struct  char_traits<char>
              {    // properties of a string or stream wchar_t element
    static void __CLRCALL_OR_CDECL assign(_Elem& _Left, const _Elem& _Right)
        {    // assign an element
        _Left = _Right;
        }
    static bool __CLRCALL_OR_CDECL eq(const _Elem& _Left, const _Elem& _Right)
        {    // test for element equality
        return (_Left == _Right);
        }
        ……
        ……
        …..
    static size_t __CLRCALL_OR_CDECL length(const _Elem *_First)
        {    // find length of null-terminated sequence
    //        _DEBUG_POINTER(_First);
        return (::strlen(_First));
        }
    };</span>
当实现了上面两个特化的模板之后,在模板basic_string中,我们如果需要知道当前模板参数类型的字符串长度时,只需要调用char_traits::length()就可以调用到正确的函数了。
3、总结
通过以上的事例,我们可以看出,具体的traits技巧非常简单。也就是将因为模板形参(包括类型形参、非类型形参)不同而导致的不同,抽取到新的模板中去,然后通过模板的特化(全特化、偏特化均可,至少有一个模板形参不同即可)来分别实现其不同。 这一类的模板,都会在命名中加上traits以示区别,所以也会把运用这一类方法称为C++的traits技术。traits技术更展现出了一种编程的思想,也即将相同的提出复用,将不同的部分通过接口来实现。将模板形参与基不同的实现绑定在一起,其实与设计模式中的状态模式很相似,都体现出了相同的编程思想。只不过前者是编译时确定的,后者则是运行时确定的。
4、注意
template< typename T > 
struct is_pointer{ 
static const bool value = false; 
};
template< typename T > 
struct is_pointer< T* >{ 
static const bool value = true; 
};这样我就可以通过is_pointer<T>::value来判断当前类型是否为指针类型。Template<bool b>
Struct algo_sort
{
  Template<typename T>
  Static void sort(T& obj)
  {
     Quick_sort(obj);
  }
}
Template<>
Struct algo_sort<true>
{
  Template<typename T>
  Static void sort(T& obj)
  {
     Select_sort(obj);
  }
}这样就能够模板形参调用不同的排序方法了.template< typename T >
struct STRUCT_TYPE
{
   typedef int MY_TYPE;
   typedef LONGLONG POWER_TYPE;
};
template<>
struct STRUCT_TYPE<double>
{
    typedef float MY_TYPE;
    typedef double POW_TYPE;
};
template< typename T > 
struct STRUCT_ALGO
{
   // 下面的Typename是指示T::MY_TYPE是一个类型而不是成员变量
   // 在VS2005中加与不加均可
   typedef typename T::MY_TYPE myType;
   typedef T::POWER_TYPE powType;
        
    powType GetPow(const myType& value)
    {
       return value*value;
    }
};这样我们甚至可以将模板形参关联的变量类型也可以抽离出来,以提高模板的通用性.原文:http://blog.csdn.net/feihe0755/article/details/45618501