C++特化
来源:互联网 发布:magic mouse 知乎 编辑:程序博客网 时间:2024/06/17 14:42
最近看TCPL讲解有关template specialization 的问题,发现在讲解类模板特化对抑制代码的膨胀的问题的时候不是很清楚,自己也没有怎么看懂!最后通过查阅有关的文档,有所顿悟,不知道理解的正确不正确,先记下来再说。
为什么要特化模板呢?一个模板给出了一个单一的定义,用户可以用任何合法的参数去实例化模板参数。但是对写模板的人来说,他希望对于某些类型的模板参数,能够提供一种定义,对于其他类型的模板参数,给出模板的另外的定义。那么这个时候就要用到类模板的特化了。
在特化一个类模板之前,需要定义该类模板的一个通用的定义。例如:s
template<class T> class stack
{
private:
vector<T> v;
public:
stack();
stack(int);
T& pop();
T& top();
void push(T&);
}
我们首先定义个带一个参数的stack模板,然后我们就可以特化这个模板了。
特化类模板的格式为:以template<>大头,后跟模板名,模板名字后面紧跟特化的模板参数,下面我们定义一个到void指针的stack特化版本
template<> stack<void*>
{
private:
vector<void*> v;
public:
stack();
stack(int);
void*& pop();
void*& top();
void push(void*&);
}
stack后面的<void>说明这个定义应该用在所有的T是void的stack实现里。
stack<void*>是一个完全的专门化,即我们在使用这个专门化的时候不需要描述其模板参数。
如果要定义一个专门化,使它能够并且只能够用于所有的指针stack,那么我们就需要定义一个部分专门化。
template<> stack<T*> : private stack<void*>
{
private:
vector<T*> v;
private:
stack();
stack(int);
T*& pop(){return static_cast<T*&>(stack<void*>::pop());}
T*& top(){return static_cast<T*&>(stack<void*>::top());}
void push(T*& p){stack<void*>::push(p);}
}
这么特化stack模板以后,我们定义任何指针类型的stack,都将会选择stack<T*>这个特化来实例化。而不是之前定义的通用型的模板stack<T>来实例化。
我们这么做可以抑制代码的膨胀。因为若果没有stack<T*>特化,对于任何不同的T类型,例如我在声明类型为int*, double*,float*, char*的stack的时候,我们都将建立对应的副本,stack<int*>, stack<double*>, stack<float*>, stack<char*>,如果我们声明很多类型不同的stack,必定造成代码的膨胀。
而如果对stack做了上面的特化,我们定义任指针类型的stack时,都只有stack的一个副本出现。(个人对于上面的实现是这么理解的,就是对于每一个指针类型stack的声明,都会有一个对应的用stack<T*>实例化的代码的副本存在,但是只有一份stack<void*>的副本存在,因为stack<T*>是从stack<void*>继承下来的,那么如果我们把stack的主要实现代码都放在stack<void*>里面实现的话,stack<T*>模板只定义一个界面,其中的实现调用模板stack<T*>里的函数,那么虽然每个类型的stack都会有一个副本,但是它的代码很少,因为它的每一个成员函数仅仅是对stack<void*>里成员函数的一次调用,主要的实现都放在了stack<void*>里面,而stack<void*>只有一个副本,这样就起到了抑制代码膨胀的效果。)
为什么要特化模板呢?一个模板给出了一个单一的定义,用户可以用任何合法的参数去实例化模板参数。但是对写模板的人来说,他希望对于某些类型的模板参数,能够提供一种定义,对于其他类型的模板参数,给出模板的另外的定义。那么这个时候就要用到类模板的特化了。
在特化一个类模板之前,需要定义该类模板的一个通用的定义。例如:s
template<class T> class stack
{
private:
vector<T> v;
public:
stack();
stack(int);
T& pop();
T& top();
void push(T&);
}
我们首先定义个带一个参数的stack模板,然后我们就可以特化这个模板了。
特化类模板的格式为:以template<>大头,后跟模板名,模板名字后面紧跟特化的模板参数,下面我们定义一个到void指针的stack特化版本
template<> stack<void*>
{
private:
vector<void*> v;
public:
stack();
stack(int);
void*& pop();
void*& top();
void push(void*&);
}
stack后面的<void>说明这个定义应该用在所有的T是void的stack实现里。
stack<void*>是一个完全的专门化,即我们在使用这个专门化的时候不需要描述其模板参数。
如果要定义一个专门化,使它能够并且只能够用于所有的指针stack,那么我们就需要定义一个部分专门化。
template<> stack<T*> : private stack<void*>
{
private:
vector<T*> v;
private:
stack();
stack(int);
T*& pop(){return static_cast<T*&>(stack<void*>::pop());}
T*& top(){return static_cast<T*&>(stack<void*>::top());}
void push(T*& p){stack<void*>::push(p);}
}
这么特化stack模板以后,我们定义任何指针类型的stack,都将会选择stack<T*>这个特化来实例化。而不是之前定义的通用型的模板stack<T>来实例化。
我们这么做可以抑制代码的膨胀。因为若果没有stack<T*>特化,对于任何不同的T类型,例如我在声明类型为int*, double*,float*, char*的stack的时候,我们都将建立对应的副本,stack<int*>, stack<double*>, stack<float*>, stack<char*>,如果我们声明很多类型不同的stack,必定造成代码的膨胀。
而如果对stack做了上面的特化,我们定义任指针类型的stack时,都只有stack的一个副本出现。(个人对于上面的实现是这么理解的,就是对于每一个指针类型stack的声明,都会有一个对应的用stack<T*>实例化的代码的副本存在,但是只有一份stack<void*>的副本存在,因为stack<T*>是从stack<void*>继承下来的,那么如果我们把stack的主要实现代码都放在stack<void*>里面实现的话,stack<T*>模板只定义一个界面,其中的实现调用模板stack<T*>里的函数,那么虽然每个类型的stack都会有一个副本,但是它的代码很少,因为它的每一个成员函数仅仅是对stack<void*>里成员函数的一次调用,主要的实现都放在了stack<void*>里面,而stack<void*>只有一个副本,这样就起到了抑制代码膨胀的效果。)
- C++—模板特化和偏特化
- 【C++】模板类、特化以及偏特化!!!
- C/C++模版特化、偏特化、全特化
- 【c++】模板的特化
- C++——模板特化和偏特化
- C++——模板特化和偏特化
- Linux C/C++ 模板:主模板、完全特化、局部特化
- C++——模板特化和偏特化
- C++——模板特化和偏特化
- 特化
- C++模板的特化
- C++模板的特化
- C++:函数模板、类模板及其特化
- C++-必知必会_类模板显式特化(条款46)
- C++-必知必会_模板局部特化(条款47)
- C++-必知必会_类模板成员特化(条款48)
- Linux C/C++ 模板:主模板、完全特化
- Linux C/C++ 模板:类模板成员特化
- 时间
- javascript做的日历控件
- 08.09.24
- 前言---我的地盘---暗恋桃花源
- 日记2008.9.24
- C++特化
- 作团队感悟(15)----不能仅仅靠感情
- 钱
- Oracle编程高手箴言:位图索引(Bitmap Index)的故事
- Oracle HttpServer 无法启动的问题
- Photoshop CS3 图像锐利化教程 Exercise Files
- 利用带关联子查询Update语句更新数据
- 编译AT91BootStrap(转)
- 新的任务,新的挑战