当前位置: 首页 > news >正文

模板进阶

   

目录

   

一、非类型模板参数

二、模板的特化

1、函数模板特化

函数模板的特化步骤:

函数模板特化的调用顺序

2、类模板特化

全特化

偏特化

类模板特化实例

三、模板分离编译


一、非类型模板参数

   类中的模板参数分为类类型和非类类型。

template<class T,size_t N=10>
void fun(T& x, size_t n=N)
{cout << "void fun(T& x, size_t n)" << endl;
}

   上面我们定义了一个size_t类型的模板参数N,N可以作为常量参与具体的运算。

   需要注意的是,在C++11标准及以前,仅支持整数类型作为类的非类类型模板参数。

   这里还有个需要注意的地方:在使用模板T进行传参的时候最好进行传引用传参,因为T可能是自定义类型,而对自定义类型进行非引用传参会导致拷贝增加使得程序效率下降。

二、模板的特化

1、函数模板特化

函数模板的特化步骤:

   1. 必须要先有一个基础的函数模板

   2. 关键字template后面接一对空的尖括号<>

   3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型

   4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇 怪的错误。

   下面有一代码:

template<class T>
int add(T& x)
{return x * 2;
}

   假如我们就只想让double类型的变量乘3,那么我们就可以使用模板特化。

函数模板特化的调用顺序

   函数调用的时候会选着最符合其参数特征的那个。

template<class T, size_t N = 10>
void fun(T& x, size_t n = N)
{cout << "void fun(T& x, size_t n)" << endl;
}template<class T1,class T2>
int add(const T1& x, const T2& y)
{cout << "const T1& x, const T2& y" << endl;return x +y;
}template<>
int add<double,int>(const double& x, const int& y)
{cout << "const double& x, const int& y" << endl;return x +y;
}template<>
int add<double, double>(const double& x, const double& y)
{cout << "const double& x, const double& y" << endl;return x + y;
}int main()
{add(1, 1);add(1.0, 1);add(1, 1.0);return 0;
}

   但实际上我们更加偏向于直接给出处理特殊类型的函数,这样比模板特化更加简单。

2、类模板特化

全特化

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

template<class T1,class T2>
class text
{
public:text(){cout << "class T1,class T2" << endl;}
private: int _a;int _b;
};template<>
class text<int, int>
{
public:text(){cout << "int,int" << endl;}
private:int _a;	int _b;
};template<>
class text<int, double>
{
public:text(){cout << "int,double" << endl;}
private:int _a;int _b;
};int main()
{text < double, double> a1;text<int, int> a2;text<int, double> a3;return 0;
}

偏特化

    与全特化不同,偏特化仍需要保留 “待推导的模板参数”。

eg:

template<class T>
class text<int, T>
{
public:text(){cout << "int,T" << endl;}
private:int _a;int _b;
};template<class T1,class T2>
class text<T1*, T2*>
{
public:text(){cout << "T1*, T2*" << endl;}
private:int _a;int _b;
};

类模板特化实例

   我们特化一个fun类来用于比较数据之间的大小关系

   我们用最下面的sort模板。

template<class T1, class T2>
class Less
{
public:bool operator()(const T1& x, const T2& y){return x._a > y._a;}
};template<class T1, class T2>
class text;template<>
class text<int, int>
{
public:text(){cout << "int,int" << endl;}text(const int& x, const int& y):_a(x), _b(y){ }friend ostream& operator<<(ostream& out, const text& x);friend Less<text<int, int>, text<int, int>>;private:int _a;	int _b;
};ostream& operator<<(ostream& out, const text<int, int>& x)
{out << x._a << "-" << x._b << endl;return out;
}
int main()
{text<int,int> A(1, 2);text<int, int> B(3, 4);text<int, int> C(5, 6);text<int, int> D(7, 8);vector<text<int, int>> h;h.push_back(C);h.push_back(B);h.push_back(D);h.push_back(A);for (auto e : h){cout << e;}cout << "排序后:" << endl;sort(h.begin(), h.end(), Less<text<int,int>, text<int, int>>());for (auto e : h){cout << e;}return 0;
}

   运用Less类模板中的()符号重载,我们何以控制sort排序的方式:

当模板参数为int指针类型时,需特别注意Less类中的()重载函数的参数:

   下面还是直接给出正确写法吧(不是作者懒

template<>
class Less
{
public:bool operator()( int* const x,  int* const y){return *x > *y;}
};

   为什么const加在*号右边?因为此时Less类的模板参数为指针类型,const修饰的是模板,如果const加在*左边则不是修饰指针本身!

三、模板分离编译

   先看下面的代码:

// a.h
template<class T>
T Add(const T& left, const T& right);// a.cpp
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}// main.cpp
#include"a.h"
int main()
{Add(1, 2);Add(1.0, 2.0);return 0;
}

   当我们运行上面代码时会出现链接错误。

   这是因为当有文件在main.cpp展开时并没有看到模板的实例化,也就导致在链接的过程中找不到函数地址而报错。

   解决办法:

   1. 将声明和定义放到一个文件 "xxx.cpp" 里面或者xxx.h。

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

// 显示实例化
template <class T>
class text
{//…………
};template class text<int>;  // 关键语法:template + class + 模板名<具体类型>;

   相比较于将声明与定义不分离,模板显示实例化更加麻烦,我们平常更加推荐使用第一种声明与定义不分离方式。

http://www.dtcms.com/a/365457.html

相关文章:

  • Python/JS/Go/Java同步学习(第二篇)四语言数据基本类型对照表: 老板让我统一系统数据类型?(附源码/截图/参数表/老板沉默术)
  • GitLab Milestones 深度解析:选型、竞品、成本与资源消耗
  • 本地Merge-github有新的远程提交与本地新修改
  • 创建消息队列,完成信息传输
  • 输电线路杆塔倾斜在线监测装置:技术解析与实际应用
  • 浏览器面试题及详细答案 88道(67-77)
  • 项目中 Spring Boot 配置文件未生效该如何解决
  • 网络世界漫游指南:MAC地址、MAC层与LLC层的奇幻之旅
  • 从儒略日到航天轨道:时间与坐标系的探索之旅
  • torch学习 自用
  • Ubuntu22.04下编译googletest源代码生成.so动态库
  • 现在你问「怎么剪枝」,其实就是在 循环里面提前判断,如果后面剩下的数字不够了,就不用再递归下去了。
  • 神经网络模型介绍
  • STM32的时钟系统与时钟树的配置
  • pip的缓存
  • 嵌入式人别再瞎折腾了!这8个开源项目,解决按键/队列/物联网所有痛点,小白也能抄作业
  • 【Rhino】【Python】将开放曲面转换为边界线和填充
  • Kotlin编程学习记录2
  • H3C UIS Cell 3020 G3服务器更换raid卡安装ONEStor记录
  • Python - Union联合类型注解
  • 数据库函数详解:COALESCE 到底有什么用?
  • 微硕WINSOK超低阻抗MOS管 WSD30100DN56在汽车高性能系统中的应用
  • Ubuntu22.04中使用cmake安装abseil-cpp库
  • oracle 从一张表更新到另外一张表的方法(MERGE)
  • java面试:可以讲解一下mysql的索引吗
  • 部署MYSQL主从同步超详细过程
  • Kafka面试精讲 Day 6:Kafka日志存储结构与索引机制
  • 【stm32】定时器中断与定时器外部时钟
  • RTSP流端口占用详解:TCP模式与UDP模式的对比
  • 首届中国AI项目管理大会成功召开圆满闭幕!