C++模板的笔记1

C++ 函数模板

函数模板的定义

函数模板是一种可以生成不同类型函数的函数声明。函数模板的参数类型不是固定的,而是在调用时由实参类型推导出来。

语法:

template <typename 参数列表>
函数返回值类型 函数名(参数列表) {
函数体
}

示例:

template <typename T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}

该模板定义了一个名为 swap 的函数,该函数可以交换任意类型的两个变量。

函数模板的调用和参数推导

调用函数模板时,编译器会根据实参类型推导出模板参数类型。

示例:

int x = 1, y = 2;
swap(x, y); // 模板参数推导为 int double a = 3.14, b = 2.71;
swap(a, b); // 模板参数推导为 double

函数模板的实现原理

函数模板的实现原理是:编译器会根据模板参数类型生成具体的函数代码,然后将该代码插入到程序中。

示例:

template <typename T>
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
} // 编译器会生成以下两个函数: void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
} void swap(double& a, double& b) {
double temp = a;
a = b;
b = temp;
}

函数模板的重载

函数模板可以重载,即可以定义多个具有相同名称的函数模板,但它们的模板参数列表不同。

示例:

template <typename T>
void swap(T& a, T& b) {
// ...
} template <typename T, typename U>
void swap(T& a, U& b) {
// ...
}

第一个 swap 模板可以用于交换相同类型的两个变量,而第二个 swap 模板可以用于交换不同类型的两个变量。

函数模板的参数默认值

函数模板的参数可以设置默认值,如果在调用函数模板时没有指定参数类型,则使用默认值。

语法:

template <typename T = 默认值>
void 函数名(参数列表) {
// ...
}

示例:

template <typename T = int>
void swap(T& a, T& b) {
// ...
}

该模板中,T 的默认值为 int。

如果调用 swap 函数时没有指定参数类型,则编译器会将 T 推导为 int。

int x = 1, y = 2;
swap(x, y); // T 推导为 int

函数模板的泛化和特化

函数模板的泛化是指:函数模板可以用于处理不同类型的数据。

函数模板的特化是指:针对特定的类型,可以提供更具体的实现。

语法:

template <typename T>
void 函数名(参数列表) {
// 通用实现
} template <>
void 函数名<特化类型>(参数列表) {
// 特化实现
}

示例:

template <typename T>
void print(T value) {
cout << value << endl;
} // 对 int 类型进行特化
template <>
void print(int value) {
cout << "int: " << value << endl;
}

该模板中,print 函数针对 int 类型进行了特化,提供了更具体的实现。

调用 print 函数时,会根据实参类型选择不同的实现。

int x = 1;
print(x); // 输出 "int: 1" double y = 3.14;
print(y); // 输出 "3.14"

C++ 类模板

类模板的定义

类模板是一种可以生成不同类型类的类声明。类模板中的成员函数和成员变量的类型不是固定的,而是在类实例化时由实参类型推导出来。

语法:

template <typename 参数列表>
class 类名 {
// 类成员声明
};

示例:

template <typename T>
class Point {
public:
T x;
T y; Point(T x, T y) {
this->x = x;
this->y = y;
} void print() {
cout << "(" << x << ", " << y << ")" << endl;
}
};

该模板定义了一个名为 Point 的类,该类可以表示任意类型的点。

类模板的调用和参数推导

在C++17以上的编译器中,调用类模板时,编译器会根据实参类型推导出模板参数类型,你如果编译器是其他C++17以下版本,必须写上参数。

示例:

Point<int> p1(1, 2); // 实例化 Point 类,模板参数推导为 int
p1.print(); // 输出 "(1, 2)" Point<double> p2(3.14, 2.71); // 实例化 Point 类,模板参数推导为 double
p2.print(); // 输出 "(3.14, 2.71)"

类模板的编译规则

类模板的编译规则如下:

  • 类模板本身不会被编译,只有在类实例化时才会被编译。
  • 类模板中的成员函数和成员变量的类型必须是模板参数类型或其他依赖于模板参数类型的类型。

类模板的参数默认值

类模板的参数可以设置默认值,如果在实例化类模板时没有指定参数类型,则使用默认值。

语法:

template <typename T = 默认值>
class 类名 {
// 类成员声明
};

示例:

template <typename T = int>
class Point {
public:
T x;
T y; Point(T x, T y) {
this->x = x;
this->y = y;
} void print() {
cout << "(" << x << ", " << y << ")" << endl;
}
};

该模板中,T 的默认值为 int。

在C++17以上的编译器中,如果在实例化 Point 类时没有指定参数类型,则编译器会将 T 推导为 int。

Point p1(1, 2); // T 推导为 int
p1.print(); // 输出 "(1, 2)"

类模板的泛化与特化

类模板的泛化是指:类模板可以用于表示不同类型的數據。

类模板的特化是指:针对特定的类型,可以提供更具体的实现。

语法:

template <typename T>
class 类名 {
// 通用实现
}; template <>
class 类名<特化类型> {
// 特化实现
};

示例:

template <typename T>
class Number {
public:
T value; Number(T value) {
this->value = value;
} void print() {
std::cout << value << std::endl;
}
}; // 对 int 类型进行特化
template <>
class Number<int> {
public:
int value; Number(int value) {
this->value = value;
} void print() {
std::cout << "int: " << value << std::endl;
}
};

该模板中,Number 类针对 int 类型进行了特化,提供了更具体的实现。

调用 Number 类的 print 函数时,会根据实参类型选择不同的实现。

Number<int> n1(1);
n1.print(); // 输出 "int: 1" Number<double> n2(3.14);
n2.print(); // 输出 "3.14"

类模板的成员函数模板

示例解析:

  • 该代码定义了一个名为 Num 的类模板,该类模板可以表示任意类型的数字。
  • Num 类模板有两个成员函数模板:show1 和 show2 和 show3。
  • show1 函数模板可以接受任意类型的参数。
  • show2 在外部实现的,函数模板可以接受任意类型的参数。
  • show3 函数模板的参数类型必须与类模板的参数类型相同,并且特例化成int类型。

代码示例:

#include <iostream>
using namespace std;
template <typename T>
class Num{
public:
template <typename T2> //成员方法模板泛化,类内部实现
void show1(T2 data){
cout<<"show1"<<endl;
}
template <typename T3> //成员方法模板泛化,类外实现
void show2(T3 data); void show3(int data);//成员方法特化,类外实现 };
template <typename T>
template <typename T3>
void Num<T>::show2(T3 data)
{cout<<"show2"<<endl;} template <typename T>
void Num<T>::show3(int data)
{cout<<"show3"<<endl;} int main()
{
Num<int> n;
n.show1(1);
n.show2<double>(2);
n.show3(0);
return 0;
}

知识点:

  • 类模板可以拥有成员函数模板。
  • 成员函数模板的参数可以与类模板的参数相同或不同。
  • 成员函数模板的定义需要在类模板的声明之后。
  • 成员函数模板的实现在类模板的外部需要加上,格式:
template <typename T>
template <typename T3>
返回类型 类名<T>::方法(模板参数类型 参数){}
  • 类模板可以拥有特化版成员函数模板,格式:
template <typename T>
返回类型 类名<T>::方法(指定的参数类型 参数){}
  • 类模板的成员函数不能声明为虚函数,C++ 标准规定:类模板的成员函数不能声明为虚函数,这是因为虚函数需要在运行时进行动态绑定,而类模板在编译时无法确定具体的类型。
template <typename T4>
virtual void show4(T4 data){}
//这个代码是错误的,编译会出错

拷贝构造函数模板

代码示例:

#include <iostream>

template <typename T1>
class C{
public:
C(){
std::cout<<"without parameters"<<std::endl;
}
//模板拷贝构造函数 
template<class T2>
C(const C<T2> &c2){
std::cout<<"template copy constructor"<<std::endl;
}
//模板拷贝赋值操作符重载
template<class T3>
C<T1> & operator=(const C<T3> &c3)
{
std::cout<<"template copy assignment"<<std::endl;
return *this;
}
}; int main()
{
C<int> c;    //这里是无参数默认构造 输出without parameters
//C<int> c2(c); //这里没有拷贝构造 无输出 ,因为这里c2的模板参数和c一样
//c=c2;       //这里没有拷贝赋值 无输出 ,因为这里c2的模板参数和c一样
C<double> c2(c);  //这里发生了拷贝构造 输出template copy constructor
c=c2;    //这里发生了拷贝赋值 template copy assignment
return 0;
}

知识点:

  • 两个模板参数相同的时候,调用无参数默认构造
  • 两个模板参数不相同的时候,才会调用模板拷贝构造方法和拷贝赋值操作符

C++ 模板的笔记1的更多相关文章

  1. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  2. OpenERP QWeb模板标签笔记

    在OpenERP中,通过QWeb来对模板进行渲染后加载到浏览器中,而模板中有许多的标签来定制各种需求变化,在这里记录学习过程中碰到的标签定义,以方便查询. 模板中的标签统一都是以"t-&qu ...

  3. 初步C++类模板学习笔记

    类模板 实现:在上课时间的定义给它的一个或多个参数,这些参数代表了不同的数据类型.                              -->抽象的类. 在调用类模板时, 指定參数, 由编 ...

  4. handlebar JS模板使用笔记

    直接上代码: (定义模板) (编译注入) ***知识点*** //数据必须为Json数据(强调:jsonp数据不行,和json是两种数据,jsonp多了callback回调函数来包裹json数据) 遍 ...

  5. tornada模板学习笔记

    import tornado.web import tornado.httpserver import tornado.ioloop import tornado.options import os. ...

  6. 潭州课堂25班:Ph201805201 django 项目 第五课 静态页面转为模板 (课堂笔记)

    一.分析静态页面   1.静态vs动态 条目 静态页面 动态页面 网站内容 固定不变 经常变动 浏览器加载速度 更快(无需向服务器发起请求) 更慢 改变网站内容 很难(修改或者创建新的html页面) ...

  7. smarty详细使用教程(韩顺平smarty模板技术笔记)

    MVC是一种开发模式,强调数据的输入.处理.显示是强制分离的 Smarty使用教程1.如何配置我们的smarty解压后把libs文件夹放在网站第一级目录下,然后创建两个文件夹templates 存放模 ...

  8. C++模板学习笔记

    一个有趣的东西:实现一个函数print, 输入一个数组, 输出数组的各个维度长度. eg. ], b[][], c[][][]; print(a); //(2, 4) print(b); //(3, ...

  9. 《C++ Primer Plus》14.4 类模板 学习笔记

    14.4.1 定义类模板下面以第10章的Stack类为基础来建立模板.原来的类声明如下:typedef unsigned long Item; class Stack{private:    enum ...

  10. C++Array类模板编写笔记

    C++Array类模板 函数模板和类模板都属于泛型技术,利用函数模板和类模板来创建一个具有通用功能的函数和类,以支持多种不同的形参,从而进一步简化重载函数的函数体设计. 声明方法:template&l ...

随机推荐

  1. Ant Design Vue中Table的选中详解

    <template> <a-table :columns="columns" :data-source="data" :row-selecti ...

  2. 【代码分享】使用 avx2 + 查表法,优化凯撒加密

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 接上一篇:[代码分享]使用 avx512 + 查表法,优化 ...

  3. SqlSugar分组查询

    一.分组查询和使用 1.1 语法 只有在聚合对象需要筛选的时候才会用到Having,一般分组查询用不到可以去掉   var list = db.Queryable<Student>()   ...

  4. 驱动开发:如何枚举所有SSDT表地址

    在前面的博文<驱动开发:Win10内核枚举SSDT表基址>中已经教大家如何寻找SSDT表基地址了,找到后我们可根据序号获取到指定SSDT函数的原始地址,而如果需要输出所有SSDT表信息,则 ...

  5. 你天天用4G 这些基本常识都知道吗?

    不少朋友在选购4G智能手机的时候,经常可能会遇到这样的名词,五模十三频.五模十七频.双4G.移动4G.联通4G.那这些名词到底是什么意思呢?它们之间又有什么区别呢? 其实上面的这些说法其实都是比较具有 ...

  6. Leetcode刷题第六天-回溯

    131:分割回文串 链接:131. 分割回文串 - 力扣(LeetCode) for 遍历字符串 递归切割,切割到字符串尾,单次结束 1 class Solution: 2 def partition ...

  7. php+html5使用FormData对象提交表单及上传图片的方法

    php+html5使用FormData对象提交表单及上传图片的方法 本文实例讲述了php+html5使用FormData对象提交表单及上传图片的方法.分享给大家供大家参考.具体分析如下: FormDa ...

  8. 【奶奶看了都会】ComfyUI+SVD制作AI视频教程,附效果演示

    AI一天,人间一年 大家好啊,我是小卷,最近AI绘画又发展出一些新玩意了,小卷因为工作的关系有一个月没关注AI的发展了,都有点跟不上版本节奏了... 1.comfyui的使用效果 今天给大家介绍下AI ...

  9. STM8 bootloader 升级方案程序设计(一)

    1.前言 上一篇单片机 IAP 功能基础开发篇之APP升级(一)讲到了单片机 IAP 功能给 APP 程序升级的设计思路,这篇介绍的是具体实现方式. 这篇介绍关于 STM8 系列实现 bootload ...

  10. CF1842

    A 比两边和的大小即可. B 显然如果一个数拥有的所有二进制位的 \(1\) 被包含在 \(x\) 中,选了一定不会导致不能变成 \(x\):如果有一个 \(1\),\(x\) 对应的位上是 \(0\ ...