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

C+++STL(一)

/

文章目录

  • 模版
    • C++作为静态类型语言
    • 宏可以摆脱数据类型的限制
    • 利用宏构建通用函数框架
  • 函数模版
    • 函数模版的定义
    • 函数模版的使用
    • 函数模版的分析
    • 实例化函数模版的条件
  • 函数模版扩展
    • 二次编译
    • 隐式推断类型实参
    • 函数模版的重载

bilibili 学习网址:https://www.bilibili.com/video/BV1NN4y1F7aY?spm_id_from=333.788.videopod.episodes&vd_source=0fc2f5466dc167b62ed0e5b774c4ab58

模版

C++作为静态类型语言

C++具有很多的数据类型(基本类型,类类型),在效率和类型安全上是无可比拟的。

但这种语言在很大程度上限制了程序员编写通用代码。

程序员不得不为每一种数据类型编写完全相同或近乎完全相同的代码实现,虽然他们在抽象层面是一致的。

#include <iostream>using namespace std;int max_int(int x, int y) {return x > y ? x : y;
}double max_double(double x, double y) {return x > y ? x : y;
}string max_string(string x, string y) {return x > y ? x : y;
}

宏可以摆脱数据类型的限制

宏是在预处理阶段针对代码的纯文本替换。

宏本身没有函数的语义(不会对数据类型进行检查)。

虽然可以摆脱类型的约束和限制,但同时也丧失了对数据类型的检查。

# include <iostream>using namespace std;#define Max(x, y) (x>y?x:y)int main() {int nx = 10, ny = 20;double dx = 12.3, dy = 45.6;string sx = "hello", sy = "world";//      会被替换成(nx>ny?nx:ny)cout << Max(nx, ny) << endl;cout << Max(dx, dy) << endl;cout << Max(sx, sy) << endl;// char cx[256] = "world", cy[256] = "hello";//         (cx>cy?cx:cy) 但这只比较了指针的大小,而没有比较字符串// cout << Max(cx, cy) << endl;
}

利用宏构建通用函数框架

通过实例化宏,让预编译器在编译过程中生成相应的函数。

但是代码可读性差。

# include <iostream>using namespace std;// 定义宏函数
#define Max(T) T max_##T(T x, T y) {\return x > y ? x : y; \
}// 实例化宏
Max(int)
// int max_int(int x, int y) { return x > y ? x : y; }Max(double)
// double max_double(double x, double y) {....}Max(string)
// string max_string(string x, string y) {....}// 解决代码可读性
# define Max(T) max_##T
int main() {int nx = 10, ny = 20;// cout << max_int(nx,ny) << endl;cout << Max(int)(nx,ny) << endl;double dx = 12.3, dy = 45.6;// cout << max_double(dx,dy) << endl;cout << Max(double)(dx,dy) << endl;string sx = "world", sy = "hello";cout << Max(string)(sx,sy) << endl;// cout << max_string(sx,sy) << endl;// 类型安全由程序员编写char cx[256] = "world", cy[256] = "hello";cout << Max(string)(cx,cy) << endl;return 0;
}

函数模版

函数模版的定义

  • 函数模版的定义形式:

    template<class 类型形参1, class 类型形参2, ...>
    返回值类型 函数模版名(调用形参1, 调用形参2, ...) {.... // 代码段
    }template<class T>T Max(T x, T y) {return x > y ? x : y;
    }
    

类型形参接受的是类型,调用形参接受的是数据。可以使用任何标识符作为类型形参的名称,但使用“T”已经成为了一种惯例。“T”表示调用者在使用这个函数模版时指定的任意数据类型。

函数模版的使用

使用函数模版必须对函数模版进行实例化。以下是实例化形式:

# include <iostream>using namespace std;template<class T>T Max(T x, T y) {return x > y ? x : y;
}
// 函数模版名<类型实参1, 类型实参2, ...>(调用形参1, 调用实参2, ...)
int main() {int nx = 10, ny = 20;cout << Max<int>(nx,ny) << endl;double dx = 12.3, dy = 45.6;cout << Max<double>(dx,dy) << endl;string sx = "hello", sy = "world";cout << Max<string>(sx,sy) << endl;
}

函数模版的分析

  • 编译器并不是把函数模版编译成一个可以处理任何数据类型的单一实体

  • 编译器在实例化函数模版时根据类型实参从函数模版中产生一个真正的函数实体

  • 函数模版并不是一个函数实体,通过实例化才能产生真正的函数实体

  • 函数模版可以看成是编译器生成函数实体的一个依据而已

  • 这种用具体数据类型替换函数模版类型形参的过程叫做实例化,这个过程将产生一个函数模版的实例(函数实体)

  • 只要使用函数模板,就会自动引发编译器的实例化过程,因此程序员不需要额外地请求对函数模版的实例化

实例化函数模版的条件

  • 原则上来说可以使用任何类型来实例化函数模版,不管其为数据类型还是类类型

  • 前提是这个类型必须支持函数模版所要执行的操作。

例如:一个不支持“>”操作符的类型来实例化Max函数模版,编译器将报错。

# include <iostream>using namespace std;class Interger{
public:Interger(int i)m_i(i){}// 重载Interger类型里面的操作符>bool operator>(Interger const& that)const{return m_i>that.m_i;}
private:int m_i;
};template<class T>T Max(T x, T y) {return x > y ? x : y;
}int main() {Interger ix = 100, iy = 200;// 在没有重载操作符">"之前,编译是会报错的cout << Max<Interger>(ix,iy) << endl;
}

函数模版扩展

二次编译

编译器对函数模版都会进行两次编译

  • 第一次编译发生在实例化函数模版之前(产生真正函数实体之前),只检查函数模版本身内部代码,查看基本词法是否正确。

    1. 函数模版内部出现的所有标识符是否均有声明

    2. 已知类型的调用要查看调用是否有效

    3. 对于未知类型调用认为都合理

    # include <iostream>using namespace std;class A {
    public:void func(){cout << "A:func()" << endl;}
    };template<class T>T foo() {// 标识符未声明,编译不通过fsfasfasjnf;// 已知类型调用查看调用是否有效A a;a.func();// cal()未声明,调用无效a.cal();// 未知类型的调用都认为合理T t;// 合理调用t.fisjadj();
    }int main() {return 0;
    }
    
  • 第二次编译发生在实例化函数模版之后(产生真正函数实体之后)结合所使用的类型实参,再次检查模版代码,查看所有调用是否真的均有效。

  • 第一次编译报错,谈不上第二次编译。

# include <iostream>using namespace std;class A {
public:void func(){cout << "A:func()" << endl;}
};template<class T>T foo() {// 标识符未声明,编译不通过fsfasfasjnf;// 已知类型调用查看调用是否有效A a;a.func();// cal()未声明,调用无效a.cal();// 未知类型的调用都认为合理T t;// 合理调用t.fisjadj();
}int main() {// 会报错,因为A里面没有声明fisjadj()函数foo<A>();return 0;
}

隐式推断类型实参

  • 如果函数模版的调用形参和类型形参相关。

例如:template<class T>T Max(T x, T y){...}

  • 那么在实例化函数模版时即时不显示指明函数模版的类型实参,编译器也有能力根据调用实参的类型隐式推断出正确的类型实参的类型。

例如:Max(123,456)→Max<int>(123,456)

函数模版的重载

待续…

http://www.xdnf.cn/news/527023.html

相关文章:

  • 自制操作系统day4(c指针)(指针和数组)(CLI和STI)(EFLAGS)
  • Flink概述
  • 问题 | 代码审查:函数是否包含返回语句
  • C++11特性
  • 计算机视觉设计开发工程师学习路线
  • 远程数据采集智能网关支持下的雨洪资源分布式监测网络搭建实践
  • 【每天一个知识点】embedding与representation
  • 关于 Web 漏洞原理与利用:2. XSS(跨站脚本攻击)
  • Scala 访问修饰符
  • java基础-关键字:static、单例模式
  • JDBC指南
  • 【线下沙龙】NineData x Apache Doris x 阿里云联合举办数据库技术Meetup,5月24日深圳见!
  • [[春秋云境] Privilege仿真场景
  • ElasticSearch 8.x 快速上手并了解核心概念
  • 比较两个用于手写体识别的卷积神经网络(CNN)模型
  • PostgreSQL基本用法
  • 谷歌 NotebookLM 即将推出 Sparks 视频概览:Gemini 与 Deep Research 加持,可生成 1 - 3 分钟 AI 视频
  • 前缀和——和为K的子数组
  • 光纤克尔非线性效应及其在光通信系统中的补偿教程-3.2 克尔效应
  • 分布式与集群:概念、区别与协同
  • 没有 Mac,我如何用 Appuploader 完成 iOS App 上架
  • RabbitMQ的简介
  • React集成百度【JSAPI Three】教程(002):设置不同的环境效果
  • 数据结构(二) 线性表
  • java中的Servlet4.x详解
  • 湖北理元理律师事务所观察:债务服务中的“倾听者价值”
  • 深入解析Spring Boot与Kafka集成:构建高效消息驱动微服务
  • APP小程序抓包和下游代理
  • 云原生攻防2(Docker基础补充)
  • 2.微服务-配置