自学内容网 自学内容网

C++模版进阶

1.模版非类型参数

 模版参数分为类型参数和非类型参数。 类型参数是在模版列表中跟在class后的,非类型参数就是用一个常量作为模版的一个参数。(一般是int size_t 等整形家族作为常量)

#include <iostream>
using namespace std;

template<class T,size_t N = 10>
class my_array
{
public:
T& operator[](size_t index) { return _array[index]; }
private:
T _array[N];
size_t _size;
};

int main()
{
my_array<char> a;
my_array<char, 10000> a1;

return 0;
}

2.模版的特化

2.1概念

使用模版是为了可以编写一些与类型无关的代码,但是对于一些类型我们需要特殊处理,这时就引入了模版特化。模版特化就是,在原有模版的基础上,针对特殊类型进行特殊化的实现方式。模版特化分为函数模版特化和类模版特化

2.2函数模版特化

template<class T>
bool my_greater(const T& a1, const T& a2)
{
return a1 > a2;
}

int main()
{
int a = 10;
int b = 8;
cout << my_greater(a, b) << endl;//正常比较
int* pa = &a;
int* pb = &b;
cout << my_greater(pa, pb) << endl;//错误比较,因为实际上比较的是指针的大小,而不是比较指针指向的元素的大小

return 0;
}

观察上述代码,我们发现第二个my-greater比较的是指针的大小,而不是比较的指针指向的元素的大小,此时我们就需要特化Add模版。

特化规则如下:

1.必须有一个基础的模版;2.template后面加<>;3.函数名后面加上<>,里面的内容是需要特化的类型 4.函数参数列表必须和末班函数的参数列表一一对应。

template<class T>
bool my_greater( T a1,T a2)
{
return a1 > a2;
}
template<>
bool my_greater<int*>( int*a1,  int* a2)
{
return *a1 > *a2;
}

但是一般都是将该函数直接写出,因此函数模版不建议特化 

template<class T>
bool my_greater( T a1,T a2)
{
return a1 > a2;
}

bool my_greater( int*a1,  int* a2)
{
return *a1 > *a2;
}

2.3类模版特化

2.3.1全特化

template<class T1,class T2>
class my_data
{
private:
T1 _a;
T2 _b;
};
//全特化
template<>
class my_data<int, char>
{
private:
int _a;
char _b;
};

2.3.2偏特化

//偏特化
template<class T1>
class my_data<T1, char>
{
private:
T1 _a;
char _b;
};

2.3.3参数限制特化

//限制特化
template<class T1,class T2>
class my_data<T1*, T2*>
{
private:
T1 _a;
T2 _b;
};//当参数是指针类型时调用此类模拟

 3.模版分离编译

3.1为什么需要分离编译

在工程文件中我们常常将声明写在.h文件中,定义写在.cpp文件中。这样就实现了分离编译,方便后续的查看和维护。

3.2为什么模版不能分离编译

如果我们在add.h中声明模版函数,在add.cpp中定义了模版函数,在text.cpp中使用了类;

生成可执行程序一共分为4部:

1.预处理:展开头文件,宏替换,删除注释,条件编译。生成.i文件

add.h在text.cpp和add.cpp中展开,他们分别生成了add.i和text.i文件

2.编译:语法检查,转换为汇编语言。生成.s文件

add.s,text.s

3.汇编:将汇编语言转换成二进制机器码。生成.obj文件

add.obj,text.obj

4.链接:将多个.obj文件合成成为一个

此时就出现了问题,在text.s中会有call add(?)的汇编指令去寻找add函数地址,但是add.obj中add只是一个模版,并没有实例化出具体函数,因此在符号表中就找不到add名称和地址。因此会出现链接错误的报错。

3.3解决办法:

声明和定义放在同一个文件中,或者在模版定义位置显示实例化(一般不用)

4总结模版

4.1优点

提高代码的复用率,增强代码的灵活性。

4.2缺点

每次调用函数时都会实例化出一份函数,使得代码膨胀,编译时间变长。

模版编译错误时,难以定位错误位置。


原文地址:https://blog.csdn.net/klausur31/article/details/143027823

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!