C++ 泛型编程(二) 函数模版

2023-11-11

前文回顾:
C++ 泛型编程(一) 基本概念

函数模版

  1. 模版定义

    ①.定义

    模版定义以关键字 template 开始,后跟尖括号包围的模版参数列表,用关键字 typename 来定义模版参数类型。

    template <typename T>
    int compare(const T &V1,const T &v2)
    {
        if( v1 < v2 ) return -1;
        if( v2 < v1 ) return 1;
        return 0;
    }
    

    模版的声明必须包含模版参数,模版定义中模版参数名可以与声明不同。

    template <typename T> int compare(const T &,const T &);
    

    ②.模版调用

    模版调用有两种方式:自动调用和显式调用。自动调用是由编译器根据函数实参来推导模版实参;显式调用是我们明确的告诉编译器模版实参类型。

    template <typename T>
    int compare(const T &v1,const T &v2)
    {
        if( v1 < v2 ) return -1;
        if( v2 < v1 ) return 1;
        return 0;
    }
    //
    cout << compare(1,2) << endl;//自动调用,编译器推断出 T 为 int
    cout << compare<int>(1,2) << endl;//显式调用,明确的告诉编译器 T 为 int 
    

    ③.实例化

    模版实现类型的抽象,是 C++ 重要的代码复用方式;编译器会根据推断出来的类型在编译阶段会为我们生成一份实例代码。

    cout << compare(1,2) << endl;
    //以上调用编译器推断出 T 为 int,编译器会把 T 替换成 int,编写并编译以下代码
    int compare(const int &V1,const int &v2)
    {
        if( v1 < v2 ) return -1;
        if( v2 < v1 ) return 1;
        return 0;
    }
    
  2. 模版参数

    ①.定义

    类似函数参数名字,模版参数名字可以任意,通常定义为 T。参数名字不能重用,一个模版参数名在一个特定的模版参数列表中只能出现一次,并且模版内不能重用模版参数名。

    typedef double A;
    template <typename A,typename B>// A 会覆盖上文的 A
    void f(A a,B b)
    {
        A tmp = a;//tmp 类型为 A ,非 double
        double B;//错误:模版内不可以重用模版参数名
    }
    

    ②.模版类型参数

    类型参数可以看做类型说明符,可以用来指定函数的返回类型、参数类型,以及函数体内变量声明和类型转换;类型参数前必须加关键字 template 或者 class。

    template <typename T> // 模版类型参数 T
    T foo(T* P)//函数返回返回类型为 T ,函数参数类型是指向 T 类型的指针
    {
        T temp = *p;// T 类型的变量
        //
        return temp;
    }
    

    ③.非类型模版参数

    除了定义模版类型参数,也可以在模版中定义非类型参数。一个非类型参数表示一个值而非类型,其值必须是常量表达式,可用由用户提供或者编译器推断出来。

    常量表达式可以是整型,但不能定义成浮点型或者其他类型。

    template<unsigned N,unsigned M>
    int compare(const char (&p1)[N],const char (&p1)[M])
    {
        return strcmp(p1,p2);
    }
    compare("hi","mom");//可以在编译期推断出 N 和 M 的值
    //以上调用会实例化出以下版本
    int int compare(const char (&p1)[3],const char (&p1)[4]) 
    

    非类型模版参数也可以是指针,指针的实参必须是全局的、编译期可获取的。

在这里插入图片描述

非类型模版参数也可用是函数指针。

在这里插入图片描述

④.模版默认实参

类似可以给函数实参提供默认值,也可以给模版实参提供默认值,并且函数模版的默认实参不用遵循从右向左的规则进行指定,即可以给任意位置的模版参数提供默认值;模版函数的默认实参不是模版参数推导的依据,函数模版参数总是由函数的实参推导而来的。

template<typename T1 = int ,typename T2> void defFunc(T1 a,T2 b);
  1. 模版编译

    ①.模版与头文件

    只有当我们使用模版时,编译器才会实际生成代码。为了生成一个实例化版本,编译器需要掌握函数或者类模版成员函数的定义,因此模版的头文件通常既包含声明也包括定义。

    ②.模版编译

    模版直到实例化时才会生成代码,模版的编译分为三个阶段:一是编译模版本身,编译器检查语法错误;二是编译器遇到模版时,编译器检查实参数目是否正确以及参数类型是否匹配;三是模版实例化时,编译器检查类型相关的错误。

    ③.验证编译器生成了真正的函数

    可以通过两个不同类型的函数指针指向函数模版,然后打印指针值看地址是否一致。

在这里插入图片描述

  1. 外部模版

    模版在使用的时候才会进行实例化,如果相同的多个源文件中使用了相同的模版、并提供了相同的模版参数,那么每个文件中都会有该模版的一个实例,引起代码重复。一般编译器会进行优化,只保留一份代码。

在这里插入图片描述

类似外部变量的声明,可以用 extern 关键字来声明一个外部的模版,承诺在其他位置会有一个显示的实例化定义。

#include "test.h"
template <typename T>
int compare(const T &v1,const T &v2)
{
    if( v1 < v2 ) return -1;
    if( v2 < v1 ) return 1;
    return 0;
}
template int compare(const int &v1,const int &v2);//显示实例化定义

#include "test1.h"
extern  template int compare(const int &v1,const int &v2);//实例化声明
compare(1,2);

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 泛型编程(二) 函数模版 的相关文章

  • 在 C# 中创建具有单独列的分隔文本

    我一直在尝试在 C 中创建一个制表符限制的文本文件 以便数据正确显示在单独的列中 Firstname Lastname Age John Smith 17 James Sawyer 31 我尝试过 t 字符 但我得到的只是 Firstnam
  • 使用 Unity 在构造函数中使用属性依赖注入

    好的 我在基类中定义了一个依赖属性 我尝试在其派生类的构造函数内部使用它 但这不起作用 该属性显示为 null Unity 在使用 container Resolve 解析实例后解析依赖属性 我的另一种选择是将 IUnityContaine
  • std::cout 和 std::wcout 有什么区别?

    在c 中 有什么区别std cout and std wcout 它们都控制流缓冲区的输出或将内容打印到控制台 或者它们只是相似吗 它们作用于不同的字符类型 std cout uses char作为字符类型 std wcout uses w
  • 如何检查QProcess是否正确执行?

    QProcess process sdcompare QString command sdcompare QStringList args sdcompare command sdcompare diff args sdcompare lt
  • 推导指南中的引用和值之间的差异

    考虑类型A template
  • 互斥体实现可以互换(独立于线程实现)

    所有互斥体实现最终都会调用相同的基本系统 硬件调用吗 这意味着它们可以互换吗 具体来说 如果我使用 gnu parallel算法 使用openmp 并且我想让他们称之为线程安全的类我可以使用boost mutex用于锁定 或者我必须编写自己
  • 单元测试一起运行时失败,单独运行时通过

    所以我的单元测试遇到了一些问题 我不能只是将它们复制并粘贴到这里 但我会尽力而为 问题似乎是 如果我一项一项地运行测试 一切都会按预期进行 但如果我告诉它一起运行测试 则 1 5 将通过 TestMethod public void Obj
  • C++中的类查找结构体数组

    我正在尝试创建一个结构数组 它将输入字符串链接到类 如下所示 struct string command CommandPath cPath cPathLookup set an alarm AlarmCommandPath send an
  • 将 System.Windows.Input.KeyEventArgs 键转换为 char

    我需要将事件参数作为char 但是当我尝试转换 Key 枚举时 我得到的字母和符号与传入的字母和符号完全不同 如何正确地将密钥转换为字符 这是我尝试过的 ObserveKeyStroke this new ObervableKeyStrok
  • C# Dns.GetHostEntry 不返回连接到 WiFi 的移动设备的名称

    我有一个 C 中的 Windows 窗体应用程序 我试图获取列表中所有客户端的主机名 下面给出的是 ra00l 来自此链接的代码示例 GetHostEntry 非常慢 https stackoverflow com questions 99
  • ASP.NET:获取自 1970 年 1 月 1 日以来的毫秒数

    我有一个 ASP NET VB NET 日期 我试图获取自 1970 年 1 月 1 日以来的毫秒数 我尝试在 MSDN 中寻找方法 但找不到任何东西 有谁知道如何做到这一点 从 NET 4 6 开始 该方法ToUnixTimeMillis
  • 如何将整数转换为 void 指针?

    在 C 中使用线程时 我面临警告 警告 从不同大小的整数转换为指针 代码如下 include
  • 批量更新 SQL Server C#

    我有一个 270k 行的数据库 带有主键mid和一个名为value 我有一个包含中值和值的文本文件 现在我想更新表格 以便将每个值分配给正确的中间值 我当前的方法是从 C 读取文本文件 并为我读取的每一行更新表中的一行 必须有更快的方法来做
  • Visual Studio 中的测试单独成功,但一组失败

    当我在 Visual Studio 中单独运行测试时 它们都顺利通过 然而 当我同时运行所有这些时 有些通过 有些失败 我尝试在每个测试方法之间暂停 1 秒 但没有成功 有任何想法吗 在此先感谢您的帮助 你们可能有一些共享数据 检查正在使用
  • 如何编写一个同时需要请求和响应Dtos的ServiceStack插件

    我需要提供本地化数据服务 所有本地化的响应 Dto 都共享相同的属性 IE 我定义了一个接口 ILocalizedDto 来标记那些 Dto 在请求端 有一个ILocalizedRequest对于需要本地化的请求 Using IPlugin
  • HttpWebRequest 在第二次调用时超时

    为什么以下代码在第二次 及后续 运行时超时 代码挂在 using Stream objStream request GetResponse GetResponseStream 然后引发 WebException 表示请求已超时 我已经尝试过
  • gcc 的配置选项如何确定默认枚举大小(短或非短)?

    我尝试了一些 gcc 编译器来查看默认枚举大小是否很短 至少一个字节 强制使用 fshort enums 或无短 至少 4 个字节 强制使用 fno short enums user host echo Static assert 4 si
  • Server.MapPath - 给定的物理路径,预期的虚拟路径

    我正在使用这行代码 var files Directory GetFiles Server MapPath E ftproot sales 在文件夹中查找文件 但是我收到错误消息说 给定物理路径但虚拟路径 预期的 我对在 C 中使用 Sys
  • 防止在工厂方法之外实例化对象

    假设我有一个带有工厂方法的类 class A public static A newA Some code logging return new A 是否可以使用 a 来阻止此类对象的实例化new 那么工厂方法是创建对象实例的唯一方法吗 当
  • 如何正确使用 std::condition_variable?

    我很困惑conditions variables以及如何 安全 使用它们 在我的应用程序中 我有一个创建 gui 线程的类 但是当 gui 是由 gui 线程构造时 主线程需要等待 情况与下面的函数相同 主线程创建互斥体 锁和conditi

随机推荐

  • 有向图和有权图的邻接矩阵表示法

    矩阵有多少行多少列 取决于顶点的个数 有向的 称作弧 v2没有发出任何胡 v3发出一条到v4的 到其他顶点都没有弧 记为0 邻接矩阵的每一行记录了什么 记录了以当前的顶点出发的弧 即出度边 以当前顶点的为弧尾的值 每一列是什么呢 比如 v1
  • Android 中自定义ViewGroup实现流式布局的效果

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 前言 自定义View与自定义ViewGroup的区别 自定义View 在没有现成的View 需要自己实现的时候 就使用自定义View 一
  • cin,cout和scanf,printf速度差距

    这道题的数据量大概在1e5左右 第1 2行为C C 输入输出加速后cin cout的耗费时间 第3行为不加速的 cin cout的时间 第4行为scanf printf的时间
  • 【51单片机实验笔记】声学篇(一) 蜂鸣器基本控制

    目录 前言 硬件介绍 PWM基础 蜂鸣器简介 原理图分析 蜂鸣器驱动电路 软件实现 蜂鸣器短鸣 蜂鸣器功能封装 总结 前言 蜂鸣器在生活中的应用实则相当广泛 通过本章你将学会制造噪声 笑 你将学会驱动它们 并发出响声 硬件介绍 PWM基础
  • 常用植被物候提取方法 (TIMESATE/R语言/Python)

    文章内容仅用于自己知识学习和分享 如有侵权 还请联系并删除 一 Background 这篇文章介绍的非常全面 物候的提取通常包含两个步骤 1 曲线的重构拟合 curve fitting 和 2 物候矩阵的提取 phenological me
  • linux系统运维工程师面试题集锦(一)

    1 常见Linux的发行版有哪些 并描述不同发行版之间的联系与区别 Fedora 是基于RHEL CentOS Scientific Linux 和Oracle Linux的社区版本 相比RHEL Fedora打包了显著的更多的软件包 SU
  • Vue使用debugger

    vue开发时会遇到需要调试代码的情况 使用debugger可以很方便的进行debug 1 build webpack dev conf js 将devtool cheap module eval source map 改为devtool e
  • datasource无法加载问题

    解决办法 将静态资源导入去掉 这里我是确保代码 jar包与yaml正确的情况下发现的 将pom文件中自己写的静态资源导入删掉
  • android 多线程异步下载文件,造轮子之 Android 多线程多任务断点续传下载器(设计篇)...

    前段时间面试 被问到 app 的自动更新是怎么做的 文件下载怎么实现的 用了多线程吗 是否支持断点续传 一下蒙逼 因为直接用第三方框架实现的文件下载 这些问题完全没想过 回来后觉得这里面其实涉及很多知识点 就打算自己动手封装一个支持多线程多
  • NLP(四十一)使用HuggingFace翻译模型的一次尝试

    本文将如何如何使用HuggingFace中的翻译模型 HuggingFace是NLP领域中响当当的团体 它在预训练模型方面作出了很多接触的工作 并开源了许多预训练模型和已经针对具体某个NLP人物训练好的直接可以使用的模型 本文将使用Hugg
  • Windows安装Maven教程

    一 Maven介绍 Maven是一种流行的构建工具 用于管理Java项目的构建过程 依赖项和项目生命周期 它提供了一种简单而灵活的方式来构建 测试和部署Java应用程序 Maven使用一个XML配置文件来定义项目的结构和构建过程 通过这个配
  • data analysis --python on Jupyter

    data cleaning data analysis 第一步 1 detect and delete wrong data 1 find the wrong data and make sure the data indeed wrong
  • 世界上最完美的公式 ----欧拉公式

    欧拉公式 在数学历史上有很多公式都是欧拉 leonhard euler 公元1707 1783年 发现的 它们都叫做 欧拉公式 它们分散在各个数学分支之中 1 分式里的欧拉公式 a r a b a c b r b c b a c r c a
  • 华为机试题输入输出总结

    华为机试题采用的是ACM模式 需要考生自行编写输入和输出 对于已经习惯了只编写函数体部分的考生来说可能会是个挑战 本人尝试根据自己在刷华为机试题过程中遇到的各种输入输出的case进行梳理 希望能够帮助大家尽快适应华为机试题的输入输出模式 减
  • LuatOS-SOC接口文档(air780E)--dac - 数模转换

    dac open ch freq mode 打开DAC通道 并配置参数 参数 传入值类型 解释 int 通道编号 例如0 int 输出频率 单位hz int 模式 默认为0 预留 返回值 返回值类型 解释 true 成功返回true 否则返
  • C++ traits编程方法

    转自 http s99f blog 163 com blog static 35118365200903111941380 侯捷老师在 STL 源码剖析 说 traits编程方法是一把开启STL源代码大门的钥匙 其重要性也就不必再说了 既然
  • Eclipse如何给main方法传值

    import java util Arrays 这是一个测试类 用来研究main方法的传值问题 author HHB public class Test 这是类的主方法 可以用来接受用户的输入 并将输入数据保存到一个String类型的数组里
  • gitlab部署及整合Jenkins持续构建(四)sonarqube9.9安装和使用(一步一坑)

    文章目录 postgresql13 0安装 1 配置postgresql数据库 2 进入postgresql创建数据库 代码质量管理平台 sonarqube安装 1 前置依赖 下载 2 安装unzip并解压sonarqube并移动到 usr
  • 基础数据类型的取值范围计算方法

    一 以c 为例 1 int 整数类型 4个字节 1KB 1000B 1B就是一个字节 一个字节占8位 所以4个字节就是4 8 32位 因为在计算机的二进制中有一个符号位 32 1 31 剩下31个位置存放数字 计算 每个位置只能是0 1这两
  • C++ 泛型编程(二) 函数模版

    前文回顾 C 泛型编程 一 基本概念 函数模版 模版定义 定义 模版定义以关键字 template 开始 后跟尖括号包围的模版参数列表 用关键字 typename 来定义模版参数类型 template