对C++ templates类模板的几点补充(Traits类模板特化)

我自己搭建了博客,以后可能不太在CSDN上发博文了,https://www.qingdujun.com/。


前一篇文章《浅谈C++ templates 函数模板、类模板以及非类型模板参数》简单的介绍了什么是函数模板(这个最简单),类模板以及非类型模板参数。本文对类模板再做几点补充。


1. 缺省的模板实参

这里依旧使用上一篇文章中的array类作为例子,其中有一处改变了——就是将unsigned int N = 10后面添加了一个默认的参数10:

template<typename T, unsigned int N = 10>
class array {
public:
	array();
	T& operator[] (unsigned int index);
	constexpr unsigned int size() noexcept;
private:
	T elems[N];
	int length;
};

正是由于有默认的参数,所以如果没有指定array的大小的话,就会默认为10。

og::array<int> ai;
ai[0] = 4;
ai[2] = 123;
//ai[11] = 666; //exception

以上,并没有指定array大小为默认值10,所以ai[11]就出错了。

2. Traits编程技法——以STL迭代器为例

Traits技法主要是利用了“内嵌类型”的技巧,加上一部分编译器template参数推导的功能。能力十分强劲。咯,这里给出了一个迭代器的基类,让我们看一下STL是如何施展Traits技法的。

template <typename Category,
	typename T,
	typename Distance = ptrdiff_t,
	typename Pointer = T*,
	typename Reference = T&>
class iterator {//iterator base
public:
	typedef Category iterator_category;
	typedef T value_type;
	typedef Distance difference_type;
	typedef Pointer pointer;
	typedef Reference reference;
};

下面开始使用class template“萃取”迭代器的特性,直接祭出3个萃取器,我将它们命名为:main trait、pointer trait和pointer-to-const trait。

template <typename I>
class iterator_traits {//main trait
	typedef typename I::iterator_category iterator_category;
	typedef typename I::value_type value_type;
	typedef typename I::difference_type difference_type;
	typedef typename I::pointer pointer;
	typedef typename I::reference reference;
};

template <typename I>
class iterator_traits<I*> {//pointer trait
	typedef typename I::iterator_category iterator_category;
	typedef typename I::value_type value_type;
	typedef typename ptrdiff_t difference_type;
	typedef typename I* pointer;
	typedef typename I& reference;
};

template <typename I>
class iterator_traits<const I*> {//pointer-to-const trait
	typedef typename I::iterator_category iterator_category;
	typedef typename I::value_type value_type;
	typedef typename ptrdiff_t difference_type;
	typedef typename I* pointer;
	typedef typename I& reference;
};

以上,你可能有两点疑惑。

其一,class iterator_traits<I*>这样的写法?这种其实叫做类模板的特化,第一个main trait被称为基本模板,后面的两个则为局部特化模板。我试了,必须要有基本模板,才能有局部特化模板,否则语法报错。

其二,类似于typedef typename I::pointer pointer;这样的写法?这里有两小点需要解释:

No.1 I::pointer 这里其实要求typename I传进来的必须是iterator base类,这样才能直接取类中的public成员变量。

No.2 我们常见的为typedef unsigned int size_t这样的写法?对typename balabala…的很不熟悉,这里举个例子你就熟悉了:

typedef struct node{
	int data;
	struct node* next;
}node_t;

node_t n1;

是不是有异曲同工之妙?

好了,开始另外一个话题—— 如何利用迭代器在编译时推断出类型?

直接看例子吧!这个函数可以很方便地决定某个迭代器的value_type

template <typename Iterator>
inline typename iterator_traits<Iterator>::value_type* //返回值类型
value_type(const Iterator&) {
	return static_cast<typename iterator_traits<Iterator>::value_type*>(0);
}



©为径
2018-12-23 北京 海淀


References:
[1] STL源码剖析
[2] C++ templates(第2版)

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页