您的位置:首页 > 编程语言 > C语言/C++

C++ Templates:特化与重载

2009-11-24 15:30 127 查看
重载函数模板:

#include <iostream>
template<typename T>
int f(T)
{
return 1;
}
template<typename T>
int f(T*)
{
return 2;
}
int main()
{
std::cout << f<int*>((int*)0) << std::endl;	//输出1
std::cout << f<int>((int*)0)  << std::endl;	//输出2
}


 
f<int*>生成的重载集包含两个函数:f<int*>(int*)和f<int*>(int**)。

f<int>生成的重载集包含两个函数:f<int>(int)和f<int>(int*)。

调用实参(int*)0的类型是int*,因此,两次调用都会匹配到f<int*>(int*)。

原则上,下面的模板和它们的实例化体可以在同个程序中同时存在:
template <typename T1, typename T2>
void f1(T1, T2);
template <typename T1, typename T2>
void f1(T2, T1);
template <typename T>
long f2(T);
template <typename T>
char f2(T);


不过f1<char, char>('a', 'b');这样的调用就会产生二义性。

只有在f1这两个模板出现在不同的翻译单元时,它们的两个实例化体才可以在同个程序中同时存在。

显式特化:

全局的类模板特化:

引入全局特化需要用到下面3个标记序列:template、< 和 >。

全局特化的实现并不需要与泛型实现有任何关联,这就允许可以包含不同名称的成员函数。实际上,全局特化只和类模板的名称有关联。
template <typename T>
class S {
public:
void info() {
std::cout << "generic /n";
}
};
template <>
class S<void> {
public:
void msg() {
std::cout << "fully specialized /n";
}
};


应该使用位于类外部的普通成员定义语法来定义全局类模板特化的成员,也就是说不能指定template<>前缀。

全局模板特化和由模板生成的实例化版本不能够共存于同一个程序中:
template <typename T>
class Invalid {
};
Invalid<double> x1;
template<>
class Invalid<double>;	//错误,Invalid<double>已被实例化


全局的函数模板特化:

与类模板特化的区别在于:函数模板特化引入了重载和实参演绎两个概念

全局函数模板特化不能包含缺省的实参值:

template<> int f(int, int = 35) {    //错误

    return 0;

}

对于非内联的全局函数模板特化而言,在同个程序中它的定义只能出现一次,仍然必须确保:全局函数模板特化的声明必须紧跟在模板定义的后面,以避免试图使用一个由模板直接生成的函数。

另一种解决方案是把这个特化声明为内联函数,在这种情况下,该函数的定义就可以放在头文件中。

全局成员特化:

实现特化的语法要求给每个外围类模板加上template<>前缀,如果同时要对一个成员模板进行特化,还必须加上另一个template<>前缀来说明该声明表示的是一个特化:

template<>

    template<>

    class Outer<char>::Inner<wchar_t> {

    public:

        enum { count = 1 };

    };

 

局部的类模板特化:

template <typename T>
class List {			//基本模板
public:
void append(T const&);
inline size_t length() const;
};
template<>
class List<void*> {		//为了打破无限递归,在局部特化前面先提供一个全局特化
void append(void* p);
inline size_t length() const;
};
template<typename T>
class List<T*> {		//局部特化
private:
List<void*> impl;
public:
void append(T* p) {
impl.append(p);
}
size_t length() const {
return impl.length();
}
};


表示一个局部特化的语法包括:一个模板参数列表声明和在类模板名称后面指定的模板实参列表

局部特化声明的参数列表和实参列表的一些约束:
template<typename T, int I = 3>
class S;		//基本模板
template<typename T>
class S<int, T>		//错误,参数类型不匹配
template<typename T = int>
class S<T, 10>		//错误,不能具有缺省实参
template<int I>
class S<int, I*2>	//错误,不能有非类型的表达式
template<typename U, int K>
class S<U, K>;		//错误,局部特化和基本模板之间没有本质区别


类模板局部特化的参数个数是可以和基本模板不一样的

例:针对指向成员指针的指针
template<>
class List<void* C::*> {
public:
//针对指向void*的成员指针的特化
typedef void* C::*ElementType;
void append(ElementType pm);
inline size_t length() const;
};
template<typename T, typename C>
class List<T* C::*> {
private:
List<void* C::*> impl;
public:
//针对任何指向成员指针的指针类型的局部特化(除了指向void*的成员指针类型)
typedef void* C::*ElementType;
void append(ElementType pm) {
impl.append((void* C::*)pm);
}
size_t length() const {
return impl.length();
}
};


 

小结:

类模板特化和函数模板重载的区别:

对于特化,在看到一个调用时,只会查找基本模板,在后来需要决定调用哪一个实现的时候才会考虑具体的特化模板。

对于重载函数模板进行查找的时候,所有的重载函数模板都必须放入重载集里面,而且这些重载函数模板还可以来自不同的名字空间和类。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  templates c++ class c list