[原创文章欢迎转载,但请保留作者信息]
Justin 于 2009-12-16
这一部分其实是书中的第三章,坦白说看之前我知道什么是iterator,但是traits却是从没听过。抓紧学习啊,很重要。
所以虽然第三章标题包含了迭代器和traits,这篇笔记只侧重于traits的记录。
在简要说明迭代器(iterator)是一种智能指针(smart pointer)之后,侯捷开始介绍traits技法。(我想可以翻译为特征引导,当然他老人家也说过了,简单的术语宁可不翻译)
-
迭代器的相应类别(iterator associated types):我的理解是,在模板列表中添加一个模板变量,用来表明列表中某个迭代器的类别。
就像简历里姓名之后又要带个性别来说明此人的男/女一样。下有代码一段,高亮处为iterator associated types的应用:
template
<
class
I,
class
T
>
//
-------------
void
_func(I anIterator, T aType)
//
Level 1: this is where
{
//
we see the type of the iterator
aType TempVariable;
//
and do something
//
do whatever you like here
}
template
<
class
I
>
//
-------------
inline func(I anIterator)
//
Level 2: this is where
{
//
we extract the type, which
_func(anIterator,
*
anIterator);
//
frees the user from doing this
}
int
main(
void
)
{
int
i
=
7
; func(
&
i);
//
--------------
//
any other code
//
Level 3: this is how
}
//
user invokes our function
-
模板偏特化(template partial specialization),不太喜欢侯捷翻译的这个术语,每次看到都有头疼的感觉。 但是却也找不出个合适的词来代替,只能暂时理解为“通过限定模板函数的一部分参数类型来实现某种意义上的函数重载”,尽管这种“重载”的划分依据是函数所属的对象是通过不同的模板创建的。 OK,为了方便肠道消化,上例子(出处):
#include
<
iostream
>
using
namespace
std; template
<
class
T,
class
U,
int
I
>
struct
X
{
void
f()
{ cout
<<
"
Primary template
"
<<
endl; }
}
; template
<
class
T,
int
I
>
struct
X
<
T, T
*
, I
>
{
void
f()
{ cout
<<
"
Partial specialization 1
"
<<
endl;}
}
; template
<
class
T,
class
U,
int
I
>
struct
X
<
T
*
, U, I
>
{
void
f()
{ cout
<<
"
Partial specialization 2
"
<<
endl;}
}
; template
<
class
T
>
struct
X
<
int
, T
*
,
10
>
{
void
f()
{ cout
<<
"
Partial specialization 3
"
<<
endl;}
}
; template
<
class
T,
class
U,
int
I
>
struct
X
<
T, U
*
, I
>
{
void
f()
{ cout
<<
"
Partial specialization 4
"
<<
endl;}
}
;
int
main()
{ X
<
int
,
int
,
10
>
a; X
<
int
,
int
*
,
5
>
b; X
<
int
*
,
float
,
10
>
c; X
<
int
,
char
*
,
10
>
d; X
<
float
,
int
*
,
10
>
e; a.f(); b.f(); c.f(); d.f(); e.f(); }
执行结果是: Primary template Partial specialization 1 Partial specialization 2 Partial specialization 3 Partial specialization 4 套用前面说的简历的例子:template partial specialization很贴心的提供了针对不同性别的不同的简历。填好名字之后, 如果是男的,你就需要选择你是否考虑加入本地的足球队; 如果是女的,可能会问你生理周期是多长; 如果是春哥,也许就会要求提供原地满血复活的咒语@#¥%
-
现在到了traits——类型提取。以下列出的是常用的(好吧我承认,是书中列出来的)迭代器相关的类型。由此我们可以得知有关迭代器的更多的信息。
iterator_category - 用以提取迭代器的类别:InputIterator, OutputIterator, ForwardIterator, BidirectionalIterator, RandomAccessIterator value_type - 迭代器所指对象的类别 difference_type - 两个迭代器之间的距离,如果这两个迭代器分别指向容器的头和尾,就是该容器的大小 pointer - 返回指向对象的指针 reference - 返回与对象相关联的引用 要注意的有两点: 一是我在这里用的一些词或术语并不忠实于原作,仅仅为了我自己理解方便(且避免头疼……); 二是这些迭代器相关的类型是STL已经定义好了的。直接拿来用就可以了(通过继承iterator类就可以得到)。
-
SGI中有对STL的有益补充:__type_traits。
引用侯捷语“iterator_traits负责萃取迭代器的特性,__type_traits则负责萃取型别(type)的特性”也就是说除了以上列出的关于迭代器的traits,SGI的STL还提供了对一般类型对象的traits,罗列如下:
has_trivial_default_constructor has_trivial_copy_constructor has_trivial_assignment_operator has_trivial_destructor is_POD_type
以上五种traits,依具体对象的不同而定义(通过typedef)为__false_type或__true_type中的一个。 前面四种都好理解,如果一个类里有指针成员并且需要对它们进行动态内存分配/释放等操作,那么这四个traits都应该是__false_type的:这表明对于该类的对象,constructor/copy constructor/assignment operator/destructor是non_trivial的。 或者再直接点说,在这种情况下这些函数需要一些额外的操作(对于复制函数而言,这意味着要额外申请空间,然后再拷贝这些指针成员所指向的对象)
第五种trait中的POD没看懂,也没在侯捷的说明里找到更多解释,只好再参考了这篇资料,顺带自我扫盲一下:(或许有疏漏谬误@#¥%)
-
POD就是Plain Old Data,指的是C与C++共同支持的数据类型(可以理解为交集)
-
要一一记忆POD的类别太麻烦,脑子不够用。有个可供区分的特性,见下表:
表达式 | POD 类对象T | 非POD 类对象 T | new T | 无初始化 | 按默认方式初始化 | new T() | 总是按默认方式初始化 | new T(x) | 总是通过构造函数初始化 |
这样一来就看到一个区别:非POD对象总是会被初始化的,而POD对象并不能保证这一点。
-
另外POD对象在layout、initialization、copying、addressing上也有自己的特点,此文不是要讨论POD,如果真的忘记了,就去看
这篇资料
吧。
其实说到底,traits就是对模板中的某个/几个参数进行限定并分类,由此实现的另一层意义上的重载。(个人理解,有待纠正或补充……)
|