最近在看侯捷的《STL源码剖析》,虽然感觉自己c++看得比较深一点,还是感觉还多东西不是那么明白,这里将一些细小的东西或者概念记录一下。
有些东西是根据《C++编程思想》理解的,记录一下加深印象。
STL没有太多的OO(object oriented),基本思想是GP(Generic Programming)。模板是泛型编程最基础的东西。
这里主要针对1.9节 可能令你困惑的C++语法 所列出来的组态进行讲解,因为书上基本没什么讲解。
1、模板 template
1.1 默认模板参数
很简单的类似于函数的默认参数,只要在后面加等于具体的类名即可以了。
如:template<class T, class U = char> void f() { T a; U b; };
1.2 typename:
如果在用模板定义的函数内如果不用typename标出类名,则只能把标示符当做类的静态成员,可以访问,但却不能新建类型,
如下代码:id为嵌套的类型。此时typename的作用是通知编译器,被限定的标示符为一个类型。
template<typename T>
class M{
//typename T::id i;
T::id i;
public:
void f(){ i.g();}
};
class X{
public:
class id{
public:
void g(){
cout <<"x" <<endl;
};
};
};
当没有typename时,无法定义i,但是我用函数时确实可以的,如下:
template<typename T>
void func(){
T::id i;
i.g();
}
int main(){
func<X>();
system("pause");
}
可能是不同编译器的原因,为了程序稳定性,模板编程过程中还是最好用typename。
1.3 模板类型推断
在实例化类模板时,总是需要使用尖括号并且提供所有的非默认模板参数;然而在实例化函数模板时,经常可以省略模板参数。
如:
template< typename T> const T& min(const T& a, const T& b){
return (a<b)? a:b;
}
可以通过加尖括号来调用,也可以不,让编译器从函数的参数中推断出模板的类型,这就是类型推断。
如调用min可以如下:
int i,j;
int z= min(i,j);
但此时i,j类型必须完全一致,如果不一致,即使可以进行类型转换(如int 和 float),但是编译器依然会报错,此时必须明确指出模板类型。
1.4 偏特化
一般的往往将偏特化理解为给定模板中的部分模板参数以具体的类,余下的泛化。其实不然,在本书3.4节traits编程技法一节,提到,“所谓partial specialization 的意思是提供另一份template的定义式,而其本身仍为templatized。”,“针对(任何)template参数更进一步的条件限制所设计出来的一个特化版本”。
全特化就是所有的模板都为具体的类。
T* 特化允许用指针类型匹配的模式(也只能匹配指针类型),const T* 特化允许使用指向const的指针 类型匹配(也只能匹配指向const的指针)。
注意,类模板可以偏特化,而函数模板不可以偏特化,即函数名后不可以加<>,但是可以通过重载达到类似偏特化的效果。
当有好多个版本的函数符合模板函数规则时,为了避免二义性,编译器总是选择特化程度最高的的模板。
如 template<class T,class U> void f() { T a; U b; };
某个特化版本为 template<> void f<int,char>() { int a; char b; };
某个偏特化版本为 template<class U> void f<int,U>() { int a; U b; };
1.5模板和友元(主要是限定友元)bound friend templates
class template 的某个具体实现与friend function template的某个具体实现有一对一的关系。
友元函数模板必须提前声明,本书中写到GCC中不需要前置声明。
如下,f()为Friendly类的友元函数,都为模板。此例中两者都是int的示例,注意Friendly中的f的声明里尖括号(或者<T>,不写也很容易推断),诉编译器f是一个模板,而不是普通函数,否则编译器就会找普通函数而找不到。
template<class T> class Friendly;
template<class T> void f(const Friendly<T>&);
template<class T>
class Friendly{
T t;
public:
Friendly(const T& theT):t(theT){}
friend void f<>(const Friendly<T>&);
void g(){f(*this);}
};
template<class T>
void f(const Friendly<T>& fo){
cout << fo.t << endl;
}
void h(){
f(Friendly<int>(1));
}
int main(){
h();
Friendly<int>(2).g();
}