首页 > 代码库 > C++ Primer 学习笔记_85_模板与泛型编程 --模板特化[续]

C++ Primer 学习笔记_85_模板与泛型编程 --模板特化[续]

模板与泛型编程

--模板特化[]



三、特化成员而不特化类

除了特化整个模板之外,还可以只特化pushpop成员。我们将特化push成员以复制字符数组,并且特化pop成员以释放该副本使用的内存:

template<>
void Queue<const char *>::push(const char *const &val)
{
    char *new_item = new char[sizeof(val) + 1];
    strncpy(new_item,val,sizeof(val)+1);

    QueueItem<const char *> *pt = new QueueItem<const char *>(new_item);

    if(empty())
    {
        head = tail = pt;
    }
    else
    {
        tail -> next = pt;
        tail = pt;
    }
}

template<>
void Queue<const char *>::pop()
{
    QueueItem<const char *> *p = head;
    delete head -> item;
    head = head -> next;
    delete p;
}

类类型Queue<constchar*> 将从通用类模板定义实例化而来,pushpop函数例外。调用Queue<constchar*> 对象的pushpop函数时,将调用特化版本;调用任意其他成员时,将从类模板为constchar* 实例化一个通用版本



特化声明

成员特化的声明与其他函数模板特化一样,必须以空的模板形参表开头:

template <>
void Queue<const char *>::push(const char *const &);
template <>
void Queue<const char *>::pop();

这些声明应放在Queue类的头文件中。



四、类模板的部分特化

如果类模板有一个以上的模板形参,我们也许想要特化某些模板形参而非全部。使用类模板的部分特化可以实现这一点:

template <class T1,class T2>
class some_templates
{
    //...
};

template <class T1>
class some_templates<T1,int>
{
    //...
};

类模板的部分特化本身也是模板。部分特化的定义看来像模板定义,这种定义以关键字template开头,接着是由尖括号(<>)括住的模板形参表。部分特化的模板形参表是对应的类模板定义形参表的子集some_template的部分特化只有一个名为T1的模板类型形参,第二个模板形参T2的实参已知为int部分特化的模板形参表只列出未知模板实参的那些形参



使用类模板的部分特化

类模板的名字后面必须接着模板实参列表,前面例子中,模板实参列表是<T1,int>。因为第一个模板形参的实参值未知,实参列表使用模板形参名T1作为占位符,另一个实参是类型int,int而部分特化模板。

像任何其他类模板一样,部分特化是在程序中使用时隐式实例化:

    some_templates<int,string> foo;	//使用泛型版本
    some_templates<string,int> bar;	//使用特化版本

注意第二个变量的类型,形参为stringintsome_template,既可以从普通类模板定义实例化,也可以从部分特化实例化。为什么选择部分特化来实例化该模板呢?当声明了部分特化的时候,编译器将为实例化选择最特化的模板定义,当没有部分特化可以使用的时候,就使用通用模板定义foo的实例化类型与提供的部分特化不匹配,因此,foo的类型必然从通用类模板实例化。部分特化只用于实例化第二个类型为intsome_template类型。

部分特化的定义与通用模板的定义完全不会冲突部分特化可以具有与通用类模板完全不同的成员集合类模板成员的通用定义永远不会用来实例化类模板部分特化的成员