解读C++编程中类模板的三种特化

2025-05-29 0 40

1.类模板显式特化
为了进行特化,首先需要一个通用的版本,称主模板.主模板使用了标准库堆算法. 堆 是一种线性化的树形结构,将一个值压入一个堆中, 实际上等于将该值插入到一个树形结构中;将一个值从堆中取出就等于移除并返回堆中最大值.但在处理字符的指针时会碰钉子.堆将按照指针的值进行组织. 我们可以提供一个显式特化版本解决此问题(例1)如果希望除了一个针对const char*的Heap外,还希望提供一个针对char *的Heap;(例2)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30
//主模板

template <typename T>

class Heap

{

private:

std::vector<T> h_;

public:

void push(const T& val);

T pop();

bool empty() const //const声明在末尾表示该函数不能修改类变量

{

return h_.empty();

}

}

template <typename T>

void Heap<T>::push(const T& val)

{

h_.push_back(val);

std::push_heap(h_.begin(),h_.end());

}

template <typename T>

T Head<T>::pop()

{

std::pop_head(h_.begin(),h_.end());

T tmp(h_.back());

h_.pop_back();

return tmp;

}

例1

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28
//显示特化版本

/***********************************************

* 可以看到模板参数列表是空的,其实这根本不是一个模

* 板. 因为没有指定任何模板参数.所以模板的显式特化又被

* 称作"完全特化".

* Heap<const char*> 完全特化,不会导致模板的实例化;

* Heap<int> 特化,会导致模板的实例化;

* 编译器根据主模板的声明来检查类模板特化.

***********************************************/

template<>//注意,无任何参数,当然,它本来就不是一个模板

class Head<const char *>

{

private:

std::vector<const char *> h_;

public:

void push(const char *pval);

const char * pop();

bool empty() const //const声明在末尾表示该函数不能修改类变量

{

return h_.empty();

}

};

//再次提醒, Head<const char *>不是一个模板

void Heap<const char*>::push(const char *pval)

{

h_.push_back(pval);

std::push_heap(h_.begin(),h_.end());

}

例2

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21
/***********************************************

* C++没有要求显式特化的接口必须和主模板的接口完全

* 匹配.如该例中,没有定义主模板的empty函数,并且自行增加

* 了size和capitalize两个函数.

* 提醒:此例中不定义empty函数是不可取的,定义模板的

* 显式特化和类的派生之间虽然不存在任何技术上的联系,但

* 是用户依然可以参考类的派生的优点,让特化版本至少具有

* 主模板的基本能力.

***********************************************/

template<>//注意,无任何参数,当然,它本来就不是一个模板

class Head<char *>

{

private:

std::vector<char *> h_;

public:

void push(char *pval);

char * pop();

//注意,此处没有提供empty函数哟!!!

size_t size() const;

void capitalize();

};

2.模板局部特化
模板局部特化首先要声明的是,C++还不支持对函数模板的局部特化,所以此处我们只讨论类模板的局部特化.我们依然首先需要一个主模板.(参考类模板显式特化) 自我理解:如果针对不能的指针定义不同的完全特化,岂不是太麻烦了,有没有更好的办法呢?那就是局部特化了.(例1)提示: 局部特化它是一个模板.完全特化不是一样模板.

例1

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35
/***********************************************

* 局部特化

* 和完全特化不同,这里的Heap参数类型只是被部分的确

* 定为T*,而T是一个未指定的类型,这就是为什么说它是局部

* 特化的原因;

* 当使用一个未经任何修饰的指针类型来实例化Heap时,

* 局部特化将优先于主模板;

* 当使用const char * 或 char *(参考类模板显式特化)来

* 实例化Heap时,此时完全特化又会优先于局部特化.

* Heap<std::string> h1; 主模板 T是std::string

* Heap<std::string *> h2; 局部特化 T是std:string

* Heap<int **> h3; 局部特化 T是int *

* Heap<char *> h4; 完全特化 T是char *

* Heap<const int *> h5; 局部特化 T是const int

* Heap<int (*)()> h6; 局部特化 T是int()

***********************************************/

template <typename T>

class Heap<T *> //注意这里

{

private:

std::vector<T *>h_;

public:

void push(const T *val);

T *pop();

bool empty()

{

return h_.empty();

}

};

template <typename T>

void Heap<T *>::push(const T *val)

{

//......

}

例2

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22
/***********************************************

* 有一点很微妙但很有用:主模板的完全特化或局部特化

* 必须采用与主模板相同数量和类型的实参进行实例化,但它

* 的模板的参数并不需要具有和主模板相同的形式.

***********************************************/

//定义一个模板,有三个模板参数,书写形式如下

template <typename R,typename A1,typename A2>

//注意,局部特化中,模板参数也是三个,但书写形式可不一样喽

class Heap<R (*) (A1,A2)>

{

//......

};

Heap<char *(*) (int,int)> h7; //R是char *,A1和A2是int

//把 char *(*) (int,int) 想象成一个"指向有两个参数的非成员函数的指针"

template <class C,typename T>

class Heap<T C::*>

{

//......

};

Heap<std::string Name::*> h8;//T是string,C是Name

尽管为何需要对这些东西使用Heap只是一个猜测,先知道有这么一用法吧!

3.类模板成员特化

虽然模板的特化和类的派生之间没有任何关系, 但在特化模板的时候,不妨借鉴一下派生的精神.也就意味着一个完全特化或局部特化通常必须重新实现 主模板具备的所有能力.
例:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32
//主模板

template <typename T>

class Heap

{

private:

std::vector<T> h_;

public:

void push(const T& val);

T pop();

bool empty() const //const声明在末尾表示该函数不能修改类变量

{

return h_.empty();

}

}

//其实我们真正需要特化的是 push 和 pop两个函数.

//对比显式特化,它是通过主模板,再写一个模板显式特化版本类;

//而这里只是对类模板成员进行了单独特化.

template<>

void Heap<const char*>::push(const char *const &pval)

{

h_.push_back(pval);

std::push_heap(h_.begin(),h_.end(),strLess);

}

template<>

const char* Heap<const char*>::pop()

{

std:pop_heap(h_.begin(),h_end(),strLess);

const char* tmp = h_.back();

h_.pop_back();

return tmp;

}


注意,这些函数的接口必须和 "它们正在特化其成员" 的模板的相应接口相匹配.如例1, 就得和主模板的接口相匹配.而如果你是自己再定义的一个显式/局部特化版本类,就不需要匹配 一致.(见显式特化和局部特化),最后指出两点: 首先,除了成员函数外,其实成员也可以被显式特化,如静态成员和成员模板.其次,显式特化是为模板或模板成员提供定制版本的一种手段;而显式实例化仅仅是明确地告诉编译器去实例化一个成员.

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 解读C++编程中类模板的三种特化 https://www.kuaiidc.com/106518.html

相关文章

发表评论
暂无评论