`
java-mans
  • 浏览: 11415427 次
文章分类
社区版块
存档分类
最新评论

认清C++语言之《模板特化specialization》

 
阅读更多

模板:

1) 区分模板参数(template parameter)和模板实参(template argument),前者用于模板的声明,后者用于模板的特化中:

template<typename T> //T是一个模板参数

class Heap {.....};

//........

Heap<double> dHeap; //double是一个模板实参

2) 区分模板名字(template name)和模板idtemplate id),前者只是一个简单的标识符,后者则是指附带有模板实参列表的模板名称:

Heap //模板名字

Heap<double> //模板id

3) 区分实例化(instantiation)和特化(specialization):

对模板的特化是指以一套模板实参提供给一个模板时所得到的东西。特化可是显式进行,也可以隐式进行。

例如当我们写Heap<int>时,是在使用int实参显式特化Heap类模板;写print(13.4)时,是在使用一个double实参隐式特化print函数模板。

类模板显式特化:

1)主模板:template <typename T> class Heap;

主模板仅仅被声明为用于特化,但它通常也提供定义:

template <typename T>

class Heap //模板名字

{

public:

void push(const T &val);

T pop();

bool empty() const {return h_.empty();}

private:

std::vector<T> h_;

};

我们可以提供一个针对指向字符的指针的显式特化版本,如下:

template <>

class Heap<const char *> //模板id

{

public:

void push(const char *val);

const char* pop();

bool empty() const {return h_.empty();}

private:

std::vector<const char*> h_;

};

其中的模板参数列表是空的,但要特化的模板实参则附在模板名字后面。这个类模板的显式特化版本其实并不是一个模板,因为此时没有剩下任何未指定的模板参数了。出于这个原因,类模板显式特化通常被称为“完全特化”,以便于局部特化区分开,后者是一个模板。

模板特化是一个提供了模板实参的模板名字,Heap<const char*>语法是一个模板特化,Heap<int>也是。然而,第一个对Heap的特化将不会导致对Heap模板的实例化(因为将会使用专为const char*定义的显式特化),但第二个特化将会导致对Heap主模板的实例化。

有了这个完全特化版本,我们就可以将针对const char*Heap和其他Heap区分开了:

Heap<int> h1; //使用主模板

Heap<const char *> h2; //使用显式特化

Heap<char *> h3; //使用主模板

编译器根据主模板的声明来检查类模板特化。如果模板实参和主模板匹配,编译器将会查找一个可以精确匹配模板实参的显式特化。如果希望除了提供一个针对const char*Heap外,还希望提供一个针对char*Heap,就必须提供另一个显式特化了:

template <>

class Heap<char *> //模板id

{

public:

void push(char *val);

char *pop();

size_t size() const;

void capitalize();

//未提供empty函数

private:

std::vector<char *> h_;

};

C++并没有要求显式特化的接口必须和主模板的接口完全匹配。例如,第一个针对const char*Heap显式特化中,函数push的形参类型被声明为const char*而不是const char *&;在针对char*Heap特化中,我们添加了两个新函数sizecapitalize,这是合法的,在某些情况下是非常有用的;但我们没有提供empty函数,这也是合法的,但通常是不可取的。

局部模板特化:

1)不能对函数模板进行局部特化,所能做的就是重载它们。

2)类模板局部特化跟完全特化一样,首先需要一个通用的主模板:

template <typename T> class Heap;

局部特化的代码如下:

template <typename T>

class Heap<T *> //模板id

{

public:

void push(const T *val);

T *pop();

bool empty() const {return h_.empty();}

private:

std::vector<T *> h_;

};

局部特化的语法类似于完全特化,但它的模板参数列表是非空的。就像完全特化一样,类模板名字是一个模板id而不是一个简单的模板名字。

和类模板的完全特化不同,局部特化是一个模板,在其成员的定义中,template关键字和参数列表时不可省略的。

和完全特化不同,这个版本的Heap的参数类型并没有被完全确定,它只是被部分地确定为T*,而T是一个未指定的类型。当使用任何指针类型来实例化一个Heap时,这个局部特化版本将优于主模板而被采用。也就是说,当模板实参类型是const char*char*时,针对const char*char*的完全特化版本的Heap又将优于局部特化而被采用。

Heap<std::string> h1; //使用主模板,Tstd::string

Heap<std::string *> h2; //使用局部特化,Tstd::string

Heap<int **> h3; //使用局部特化,Tint*

Heap<char *> h4; //使用针对char*的完全特化

Heap<char **> h5; //使用局部特化,Tchar*

Heap<const int *> h6; //使用局部特化,Tconst int

Heap<int (*)()> h7; //使用局部特化,Tint ()

主模板的完全特化或局部特化必须采用与主模板相同数量和类型的实参进行实例化,但它的模板参数列表并不需要具有和主模板相同的形式。对于Heap来说,主模板带有单个类型名字参数,因此Heap的任何完全特化或局部特化都必须采用单个类型名字实参来实例化:

template <typename T> class Heap;

所以,Heap的完全特化仍然带有单个类型名字模板实参,但模板参数列表不同于主模板的模板参数列表,因为完全特化的模板参数列表是空的:

template <> class Heap<char *>;

Heap的局部特化也必须带有单个类型名字模板实参,并且在其模板头部,模板参数列表可以带有单个类型名字实参:

template <typename T> class Heap<T *>;

但它未必非得如此:

template <typename T, int n> class Heap<T[n]>;

当使用一个数组类型来特化Heap时,将会选用这个局部特化,例如:

Heap<float *[6]> h8; //使用局部特化,Tfloat*n6

更有甚者:

template <typename R, typename A1, typename A2>

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

template<class C, typename T>

class Heap<T C::*>;

有了这些额外的局部特化,就可以采用“指向带有两个参数的非成员函数”的指针对Heap进行特化;采用指向数据成员的指针进行特化:

Heap<char *(*)(int, int)> h9;

//使用局部特化,Rchar*A1A2int

Heap<std::string Name::*> h10;

//使用局部特化,TstringCname

分享到:
评论

相关推荐

    深入分析C++模板特化与偏特化

    模板特化(template specialization)不同于模板的实例化,模板参数在某种特定类型下的具体实现称为模板的特化。模板特化有时也称之为模板的具体化,分别有函数模板特化和类模板特化。 1.2函数模板特化 函数模板特化...

    C++模板之特化与偏特化详解

    对于C++模板特化和偏特化,对于别人来说,已经不是什么新东西了,但是对于我来说,的确是我的盲区,那天在群里讨论这个问题,自己对于这部分确实没有掌握,又联想到在《STL源码剖析》一书中,对于此也是有着介绍。...

    C++模板特化匹配规则

    C++模板特化匹配规则

    C++模版特化

    说起C++的模板及模板特化, 相信很多人都很熟悉,但是说到模板特化的几种类型, 相信了解的人就不是很多。我这里归纳了针对一个模板参数的类模板特化的几种类型, 一 是特化为绝对类型; 二是特化为引用,指针类型;...

    C++中有关模板的试题题型练习题

    C++模板类型题型,更全面,也可以更从中了解模板的运用与技术。

    数组特化模板类

    泛型容器的设计实现大多只是存储了类型的单个对象,而没有存储类型的多个对象,如果有这样特定的需求,容器内的元素要求都是某个类型的多个对象,那么这时就可以考虑用模板类的数组特化来实现了

    C++ 类模板、函数模板全特化、偏特化的使用

    一、类模板全特化、偏特化 #pragma once #include #include template class TC { public: TC() { std::cout &lt;&lt; "泛化版本构造函数" &lt; class TC { public: TC() { std::cout &lt;&lt; "全特化版本...

    模板的 主版本模板类、全特化、偏特化

    模板的 主版本模板类、全特化、偏特化

    函数模板完全特化 C++ Builder 示例

    函数模板完全特化 C++ Builder 示例 代码参考: 余文溪的《C++ STL --数据结构与算法实现》原书代码为控制台。 这里用 C++ Builder代码演示

    c++模板学习记录(自己)

    C++模板学习记录 模板定义 模板使用 类模板 函数模板 特化模板 编译器

    C++第59课–类模板深度剖,类模板的特化,函数模板的特化

    本文学习自 狄泰软件学院 唐佐林老师的 C++课程,文中图片源自老师课程PPT。 实验1:类模板的特化 实验2:特化的深入理解:函数模板的完全特化 实验1:类模板的特化 #include #include using namespace std; ...

    利用C++模板的C到Lua简易封装库LuaMe

    LuaMe后期版本,早期版本看我早起上传的资源。主要是优化了部分代码,支持在lua端申请结构体了,并且利用lua的垃圾回收处理内存。多处使用了条件编译,可以利用条件编译出不同特性的结构体(具体使用参考其中的代码...

    C++定义函数模板代码,可以编写通用的函数来处理多种类型的容器

    C++函数模板是一种通用的代码结构,可以用于创建可以处理多种数据类型的函数。函数模板通过参数化类型来实现代码的重用和泛化。 代码中,我们定义了一个函数模板 findMax(),用于在给定的容器中查找最大值。该函数...

    C++模板编程中只特化模板类的一个成员函数

    模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数。类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1、2个成员函数即可。在这种情况下,如果全部...

    《Qt中的C++技术》

    《Qt中的C++技术》剖析了开源开发框架Qt中的C++技术,给读者提供一个优秀的案例,以学习C++语言以及面向对象设计技术。《Qt中的C++技术》讨论了以下内容:类模板特化技术;分析比较了C++标准库、Qt对字符串、数据...

    类模板完全特化 C++ Builder演示

    编译环境: Windows 7 Service Pack 1 C++ Builder Embarcadero RAD Studio XE Version 15.0.3890.34076 代码参考: 余文溪的《C++ STL --数据结构与算法实现》原书代码为控制台。 这里用 C++ Builder代码演示

    C++ Tempates中文版

    C++泛型编程的一本好书,对于对C++泛型感兴趣的人,可以下载看看哦,这本书籍详细的讲了C++ template,模板特化,偏特化等等

Global site tag (gtag.js) - Google Analytics