模板相关

一. 编译过程

首先介绍C++程序的编译过程。编译器以源文件为编译单元,编译过程分为四个阶段:预处理,编译,汇编,链接。

预处理:处理头文件和宏定义。首先根据寻找源文件中所包含的头文件,进入头文件进行宏替换,根据条件编译修改源程序。然后把头文件的内容全部添加到当前原文件里,形成一个中间c文件。

编译:对中间的c文件进行语法检查,并将源代码编译成汇编文件。

汇编:将汇编翻译成二进制的机器码,生成obj文件。

链接:根据文件之间函数的调用关系,将obj文件链接起来,生成可执行文件。

二. 模板参数种类

类型参数和非类型参数。非类型参数就是指定数值。这个数值类型只能是整形或者?忘了。是编译期常量,因此只能用常量表达式实例化,可以用作静态数组大小。

template<typename T = int, int SIZE = 1024>
class Array
{
private:
	T arr[SIZE];
};

Array<> a;
sizeof(a)--> 4096

模板参数也可以指定默认值,方向从右向左。

三. 模板实例化

看了很多博客反而越看越乱,应该看本好书系统研究一下。现在理清的如下:
实例化就是类模板或函数模板生成具体代码的过程。

什么时候实例化

对于类模板:需要用到具体类的定义时,比如创建对象;定义类的引用或指针不需要具体定义,因此不会实例化。
对于函数模板:在函数调用和取函数地址时,会实例化。因此在类模板实例化时,不会对成员函数实例化(当调用或取地址才会)。
以上的实例化都属于隐式实例化。

实例化的方式

隐式实例化:运行(?)的时候才实例化,影响效率,往往还会进行参数推断。

显式实例化:通过模板类或模板函数声明的方式,在声明时指定模板参数,并生成具体代码,如template class TestTemplate<int>;因为在每处模板类或者模板函数使用的源文件都要有一份具体的定义,因此在每个会用到具体代码的源文件都要有一个声明。(我的理解是上述发生隐式实例化的情况,都要用声明方式,显式代替隐式,把实例化放到编译期间,提高效率)。

  1. 声明的方法是在模板类或模板函数的声明前加template。
template class TestTemplate<int>; --> TestTemplate<T>的声明
template void func(int, float, char); --->void func<T1,T2,T3>(T1 a,T2 b,T3 c);的声明
template<typename> class A; 不是显式实例化,是特化。
  1. extern优化
    因为在每个相应源文件都要生成一份代码,因此增加了编译时间,可以引入extern声明,这种声明不生成代码而是生成一个具体代码的链接,所以必须有一个不带extern的声明,生成具体代码。

特化: 因为函数模板和类模板生成的代码都是通用型的,如果想对某一类型做专门的处理,就要用到特化。我们知道c++在做重载函数调用时,先会调用参数类型最匹配的函数,这里同理。先定义好特定类型下的模板代码,当调用相应类型时就会先走特化模板函数,而不走通用型模板函数。根据特化的参数个数,也分为全特化和偏特化。(再补充例子)

三. 类模板的定义声明分离

  1. 包含编译:把类模板的定义和声明都放在头文件里。
//#test.h
template<class T>
class D { public: void f();};

template<class T>
void D<T>::f() {//do somethis...}

//main.cpp
D<int> d;
d.f();
  1. 分离编译,头文件放模板声明, 源文件放定义。
//#test.h
template<class T>
class D { public: void f();};
//test.cpp
#include "test.h"
template<class T> void D<T>::f() {//do some thing}
//main.cpp
#include "test.h"
#include "test.cpp"
D<int> d;
d.f();

因为是模板不生成代码,所以main.cpp根据头文件里的声明无法链接到源文件中的定义,所以必须把源文件也包含进来。

//另一种方式
//#test.h
template<class T>
class D { public: void f();};
//test.cpp
#include "test.h"
template<class T> void D<T>::f() {//do some thing}
template class D<int>;
//main.cpp
#include "test.h"
D<int> d;
d.f();

通过显式实例化在test.cpp中生成了代码,所以main.cpp能根据头文件链接到模板类的定义。

四. 模板类的友元

友元分为三种类型:不带参数,约束参数,非约束参数。约束参数时,类模板的类型参数也是友元的参数。对于友元要先声明,这种声明不是实例化的声明,而是特化声明(???就是这么个意思吧)。非约束参数时,friend前也要定义tempate< typename>.

template<typename> class B;//先声明

template<typename T>
class A {
	friend class B<T>;
	friend class C;
};

template<typename T>
class B{};

template作用域下不用加< T>
参考:
c++头文件,源文件的编译过程
有点乱但有点道理
有点乱但有点道理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值