自学内容网 自学内容网

C++模板-进阶

目录

非类型模板参数

 模板的特化

 函数模板特化

类模板特化

        全特化

         偏特化

模板的分离编译

        解决方式

模板的总结


非类型模板参数

        模板参数分 类型形参 和 非类型形参

        类型形参:出现模板参数列表中,跟在class或者typename之类的参数类型名称

        非类型形参:用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当常量来使用

namespace A
{
template<class T,size_t N = 10>
class arr
{
public:
T& operator[](size_t n) { return _arr[n]; }
size_t size() const { return _size; }
bool empty() const { return 0 == _size; }
private:
T _arr[N];
size_t _size;
};
}

        其中N就是非类型形参

        浮点数,类对象,字符串不可以当非类型模板参数

        非类型的模板参数必须在编译期就能确认结果 

 模板的特化

        通常情况下,使用模板可以实现一些与类型无关的代码,但是对于特殊类型也需要特殊处理

class Num
{
public:
Num(int a):_a(a){}
bool operator<(Num& b) { return _a < b._a; }

private:
int _a;
};

template<class T>
bool Less(T left, T right)
{
return left < right;
}

int main()
{
cout << Less(1, 2) << endl;//正确
Num n1(1);
Num n2(2);
cout << Less(n2, n1) << endl;//正确
Num* p2 = &n1;
Num* p1 = &n2;
cout << Less(p2, p1) << endl;//这里比的是地址 不是我们要的
return 0;
}

为了在对比指针时,转换为我们想要的对比方式,就需要对模板进行特化,就是在原模版类的基础上,针对特殊类型模板进行特殊化的实现方式,模板特化分为函数模板特化与类模板特化 

 函数模板特化

  1. 拥有原函数模板
  2. 用template<>进行特化
  3. 函数名字后也要有<>并且内部是特化类型
  4. 函数类型表:必须要和模板函数的基础参数类型相同
template<class T>
bool Less(T left, T right)
{
return left < right;
}
template<>
bool Less<Num*>(Num* left, Num* right)
{
return *left < *right;
}

类模板特化

        全特化

全特化就是将模板参数列表中的所有参数都确定化

template<class T1,class T2>
class Num
{
public:
Num(T1 a1,T2 a2):_a1(a1),_a2(a2){}
private:
T1 _a1;
T2 _a2;
};

template<>
class Num<int,char>
{
public:
Num(int a1, char a2) :_a1(a1), _a2(a2) {}
private:
int _a1;
char _a2;
};

         偏特化

        不完全的特化类型

template<class T1,class T2>
class Num
{
public:
Num(T1 a1,T2 a2):_a1(a1),_a2(a2){}
private:
T1 _a1;
T2 _a2;
};

template<class T1>
class Num<T1, int>
{
public:
Num(T1 a1, int a2) :_a1(a1), _a2(a2) {}
private:
T1 _a1;
int _a2;
};

特殊偏特化

        

template<class T1, class T2>
class Num<T1*,T2*>
{
public:
Num(T1* a1, T2* a2) :_a1(a1), _a2(a2) {}
private:
T1* _a1;
T2* _a2;
};

template<class T1, class T2>
class Num<T1&,T2&>
{
public:
Num(T1& a1, T2& a2) :_a1(a1), _a2(a2) {}
private:
T1& _a1;
T2& _a2;
};

模板的分离编译

        把多个源文件实现,单独编译,然后链接成单一可执行文件的过程叫做分离编译模式 

         在C++中,模板是一种允许程序员编写通用代码的工具,可以适应不同的数据类型和场景。然而,模板本身并不生成代码,只有当模板被实例化时,编译器才会根据模板定义生成相应的代码。这意味着,模板的实例化是在编译时进行的,而不是在链接时。

        模板定义不可见:当模板的声明与定义分离,并且定义在另一个文件中时,编译器在实例化模板时可能找不到对应的模板定义。由于模板的实例化是在编译时进行的,如果编译器在实例化模板时无法访问到模板的完整定义,那么它将无法生成正确的代码,从而导致编译或链接错误。

        符号表问题:符号表记录了程序中所有符号(如函数名、变量名等)的信息。对于模板来说,如果模板在某个源文件中被实例化,那么实例化后的函数或对象将会出现在该源文件的符号表中。但是,如果模板的声明与定义分离,且定义在另一个文件中,而这个文件在链接前没有被正确编译或包含,那么实例化后的符号可能就不会出现在最终的符号表中,从而导致链接错误。

        解决方式

        1.把声明和定义放到同一个文件里

        2.模板定义的位置显式实例化 

         实例化:

// MyClass.cpp
#include "MyClass.h"

// 显式实例化 MyClass<int> 和 MyClass<double>
template class MyClass<int>;
template class MyClass<double>;

模板的总结

优点

  1. 代码重用:模板允许创建参数化的代码,从而大大减少重复代码,提高开发效率。
  2. 类型安全:模板提供编译时类型检查,确保类型正确,减少运行时错误。
  3. 性能优化:模板实例化是在编译时进行的,编译器可以针对特定的数据类型生成高效的代码。

缺点

  1. 编译时间增加:由于模板在编译时需要实例化多个版本,因此可能会增加编译时间。
  2. 代码膨胀:模板在编译时生成大量代码,可能会导致可执行文件体积增大。
  3. 易读性和调试困难:模板代码可能较为复杂,不易阅读和理解,同时在调试时也可能更加困难。
  4. 二进制兼容性问题:由于模板实例化是在编译时进行的,因此不同编译器或不同编译选项下生成的二进制代码可能不兼容。
  5. 限制:模板的某些高级特性(如局部特殊化和特殊化顺序)在不同C++标准实现中可能不统一,限制了模板的跨平台性和可移植性。


原文地址:https://blog.csdn.net/forccct/article/details/145246542

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