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

【类模板】类模板的特化

一、类模板的泛化

与函数模板一样,类模板的泛化就是普通的模板,不具有特殊性的模板。
以下的类模板为泛化的版本

//类模板的泛化
template<typename T,typename U>
struct TC {//静态成员变量static int static_varible;  //声明TC() {std::cout << "TC泛化版本的构造函数\n";}void func1(); void func2();
};//类外实现func1
template<typename T,typename U>
void TC<T, U>::func1() {std::cout << "func1的泛化版本\n";
}//类外实现func2
template<typename T, typename U>
void TC<T, U>::func2() {std::cout << "func2的泛化版本\n";
}template<typename T,typename U>
int TC<T, U>::static_varible = 50; //定义(初始化)

这里采用的类内声明,类外定义的方法

二、类模板的全特化

1.类模板的全特化

我们可以在有泛化版本的前提下,加入一个全特化的版本,如下所示:

//类模板的全特化
template<>
struct TC<int,int> { //<>符号是必要的TC() {std::cout << "TC<int,int>的特化版本构造函数\n";}void func1() {std::cout << "TC<int,int>的特化版本func1函数\n";}void func2();//添加泛化版本中没有的函数void func3();
};

注意,我们在类外实现函数的时候不能加入 t e m p l a t e < > template<> template<>,否则会编译失败。

//类外实现func2
//注意全特化版本类外实现不能加template<>//template<>
void TC<int, int>::func2() {std::cout << "TC<int,int>的特化版本func2函数\n";}//类外实现fun3
void TC<int, int>::func3() {std::cout << "TC<int,int>的特化版本func3函数\n";
}

由于全特化版本的类已经和泛化版本的类区分开来了,因此可以添加上泛化版本没有的内容。
如我们在成员函数上增加了 f u n c 3 func3 func3函数。

2. 普通成员函数的全特化

我们这里以全特化 f u n c 1 func1 func1函数为例:

//普通成员函数的全特化
template<> //这里可加可不加
void TC<double, int>::func1() { //全特化func1成员函数std::cout << "普通成员函数TC<double,int>::func1的全特化\n";
};

成员函数的全特化可以忽略 t e m p l a t e < > template<> template<>,也可以使用。

注意,如果我们先对泛化版本添加了成员函数的全特化版本,那么我们就无法对泛化版本添加相同的全特化的类模板,因为类模板的成员函数已经被占用了。

如图:

template<> 
struct TC<double,int> { //此时TC的<double,int>版本部分内容已经被占用了TC();void func1();void func2();};

会编译失败
在这里插入图片描述

3.静态成员变量的全特化

对于静态成员函数的全特化,我们首先必须在类外定义静态成员函数的泛化版本,然后再加入全特化版本。

泛化版本的定义:

template<typename T,typename U>
int TC<T, U>::static_varible = 50; //定义(初始化)

加入全特化版本的静态成员变量:

//静态成员变量的全特化
template<> //这里可加可不加
int TC<double, int>::static_varible = 100; 

对于静态成员变量的全特化,与普通成员函数一样,已经占有了就不能再加入相同版本的全特化类模板了。

三、类模板的偏特化

函数模板不具有偏特化,而类模板可以进行偏特化。

1. 模板参数数量上的偏特化

我们可以指定类模板的某些参数类型,特殊对其进行偏特化:
下面是 T C TC TC类模板在参数数量上的偏特化版本:

//模板参数数量上的偏特化
template<typename U>
struct TC<float, U> {TC() {std::cout << "TC<float,U>偏特化版本的构造函数\n";}void fun1();
};
//类外实现
template<typename U>
void TC<float, U>::fun1() {std::cout << "TC<float,U>偏特化版本的func1函数\n";
}

通过调用,我们发现使用了偏特化版本

void Test() {TC<float,int>t;
}

如图所示:

在这里插入图片描述

2.模板参数范围上的偏特化

有时,对于一些特殊的类型参数我们要进行特殊处理,如
∗ ( 指针 ) , & ( 左值引用 ) , & & ( 右值引用 ) , c o n s t ( 常变量 ) *(指针),\&(左值引用),\&\&(右值引用),const(常变量) (指针),&(左值引用),&&(右值引用),const(常变量)
因此,我们就可以对这些变量加入偏特化版本:
下面实现一个偏特化的 T C < c o n s t T , U ∗ > TC<const \ T,U*> TC<const T,U>的版本:

//模板参数范围上的偏特化
template<typename T,typename U>
struct TC<const T, U*> { //限定T为const类型,U为指针TC() {std::cout << "TC<const T,U*>偏特化版本的构造函数\n";}void func1();
};//类外实现
template<typename T,typename U>
void TC<const T, U*>::func1() {std::cout << "TC<const T,U*>偏特化版本的func1函数\n";
}

而这样就能缩小范围,在调用时优先调用偏特化版本。
如下图所示:
:
优先使用了偏特化版本的构造函数。

当然,如果去掉了这个偏特化版本,将会调用泛化版本。

注释掉偏特化版本后,运行得到:

在这里插入图片描述
由于找不到全特化版本和偏特化版本,因此最终调用了泛化版本

3.其他

最后,对于偏特化版本的话,不存在对成员函数或静态成员变量的偏特化。
以下代码无法通过编译:

//不存在对成员函数的偏特化
template<typename U>
void TC<double, U>::func2() {std::cout << "TC<double,U>偏特化版本的func2函数\n";
}

http://www.mrgr.cn/news/18039.html

相关文章:

  • 金九银十来了,你准备好了吗?——迎接技术行业的旺季
  • SPI驱动学习三(spidev的使用)
  • 【C语言从不挂科到高绩点】06-流程控制语句-循环语句
  • 万亿秒查是真地吗?比 ORACLE 快 N 倍是不是吹牛?
  • 轻量级 AI 革命:Phi-3.5 小模型现可一键 input!浙大领头开源多模态基准上线,含 8 大类别图像问答
  • 点击刷新按钮或者按 F5、按 Ctrl+F5 (强制刷新)、地址栏回车有什么区别?
  • 青书学堂 看视频 看课时 php 懒人版
  • Spring Boot启动卡在Root WebApplicationContext: initialization completed in...
  • 换毛季来临,猫咪浮毛如何快速清理?好用的宠物空气净化器推荐
  • 网工面试题(安全)
  • kafka3.7.1 单节点 KRaft部署测试发送和接收消息
  • 2024java面试题
  • 古典显示格式解一偏微分方程并绘制结果的彩色图
  • ~/.bashrc、 ~/.bash_profile、~/.profile、 /etc/profile几个配置文件的区别
  • 【408DS算法题】033基础-判断二叉树是否是二叉排序树
  • 云计算实训40——部署nmt、部署project_exam_system项目
  • 帧中继了解
  • Centos安装node_exporter
  • 【Unity编辑器扩展】SpriteAltas资源一键转换为TMP_SpriteAsset或Sprite图集
  • shell脚本前置基础