在C++泛型编程中接触到的这个概念。
尽管C++的模板技术为泛型编程提供了支持,可以编写更加通用的代码。
但是模板参数类型的不同,往往会带来一些问题,这时候traits会是一种很好的解决方案。
"
当函数,类或者一些封装的通用算法中的某些部分会因为数据类型不同而导致处理或逻辑不同时,traits会是一种很好的解决方案。
"
比如:C++中标准库类 string和wstring的实现。
(模板实现时 参数中需要一个求字符串长度的函数,由于类型不一致,函数调用API不一致,导致了问题)
typedef basic_string<char, char_traits<char>, allocator<char> > string;
typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstring;
traits技术可以解决上面出现的问题。
我们可以再定义一个模板,其中封装了因参数类型(包括类型参数和非类型参数)不一致的相关操作,比如这里的获取字符串的长度操作。
我们将这些操作从basic_string模板中抽离出来。这其中涉及模板的全特化和偏特化。【即需要指定模板参数的具体类型】
如:
template<> struct char_traits<char>
{
};
template<> struct char_traits<wchar_t>
{
};
traits技术展现的是一种思想,将相同的操作复用,不同的操作进一步抽象成接口复用。
traits技术是一种编译期实现技术。
举个例子:
boost库中的is_pointer
template< typename T >
struct is_pointer{
static const bool value = false;
};
template< typename T >
struct is_pointer< T* >{
static const bool value = true;
};
如果某些操作需要根据类型T的不同而不同,那么我们怎么实现呢?
在模板里面增加参数,这种思路很显然不太合适。
用户使用时肯定不知道增加的参数表示什么意义。
那么,traitts的做法实际上在外面增加了一个模板。
上面的例子中,struct is_pointer中value属性都是false。
下面那小段代码,只有当传入的模板类型是指针时,value属性才为true。
因此,我们判断时,只要这么做即可:
if is_pointer::value == false then 当前类型不是指针
if is_pointer::value == true then 当前类型是指针
更进一步 ,比如在自己实现的类中,我们可以使用 is_pointer<T>::value判断当前T的类型。
另一个例子:
template <class T>
struct TestTraits
{
typedef T ret_type;
typedef T parm_type;
};
template <class T>
class Test
{
public:
typename TestTraits<T>::ret_type testFun(typename TestTraits<T>::parm_type p);
private:
T m_data;
};