C++ 学习系列 -- 模板 template

一  C++ 模板介绍?

  C++ 为什么引入模板?

      我的理解是:

C++ 引入模板的概念,是为了复用重复的代码,当某些代码除了操作的数据类型不同以外,其他逻辑全都相同,此时就适合采用模板的方式。

定义模板类或者模板函数时,只是定义了一个代码的架子,使用时需要配合上实际的数据类型,数据类型可以是基本数据类型也可以是用户自定义的类型。

官方一点的说法:

所谓模板,实际上是建立一个通用函数或类,其类内部的类型和函数的形参类型不具体指定,用一个虚拟的类型来代表。这种通用的方式称为模板。

模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。

这种模板的设计在许多编程语言中是由类似的,比如 Java 、Scala 中都有模板的概念。

二  class template 类模板

类模板例子:

// complex.h
template<typename T>
class Complex
{
public:
    Complex(T re = 0, T im = 0):m_re(re), m_im(im)
    {

    }

    Complex& operator+=(const Complex& other);

    T real() const
    {
        return m_re;
    }

    T imag() const
    {
        return m_im;
    }


private:
    T m_re;
    T m_im;
};


template<typename T>
Complex<T>& Complex<T>::operator+=(const Complex& other)
{
    this->m_re += other.m_re; // 任意一个类都是自己的 friend class,所以可以使用 private 成员变量
    this->m_im += other.m_im;
    return *this;
}

// main.cpp
#include"complex.h"

int main()
{
    Complex<double> c1(1, 2);
    Complex<int>    c2(1.1, 2.2);
    Complex<float>  c3(1.1, 2.2);

    return 0;
}

上面是一个复数 Complex模板类的简单实现。

三  function template 函数模板

// complex.h
template<typename T>
class Complex
{
public:
    Complex(T re = 0, T im = 0):m_re(re), m_im(im)
    {

    }

    bool operator<(const Complex& other) const
    {
        if(this->m_re < other.m_re)
        {
            return true;
        }
        else if(this->m_re > other.m_re)
        {
            return false;
        }
        else
        {
            if(this->m_im < other.m_im)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    T real() const
    {
        return m_re;
    }

    T imag() const
    {
        return m_im;
    }


private:
    T m_re;
    T m_im;
};

// main.cpp
#include <iostream>
#include"complex.h"

// 模板函数
template<typename T>
const T& myMin(const T& a, const T& b)
{
    return a < b ? a : b;
}

int main()
{
      int a1 = 11;
      int b1 = 22;
      std::cout << myMin(a1, b1) << std::endl;

      double a2 = 1.1;
      double b2 = 2.2;
      std::cout << myMin(a2, b2) << std::endl;
      
      Complex<int> c11(11, 2);
      Complex<int> c12(1, 22);

      auto cc = myMin(c11, c12);
      std::cout << cc.real() << ", " << cc.imag() << std::endl;
  
      return 0;
}


       以上代码定义了一个模板函数 myMin ;一个模板类 Complex,自定义了一个 operator< 成员函数。

      从代码中我们发现一个问题,模板类要用尖括号指明实际的元素类型,而模板函数并不需要尖括号指明实际的元素类型。这是因为在 C++ 中,模板函数在调用时,可以通过传入的实参推断出形参的类型,因而不需要指明实际的元素类型。

      模板函数 myMin 传入的类型需要有比较的能力,c++ 基本类型天然就具有比较的能力,而用户自定义类型需要实现 operator< 成员函数,才能在编译到 < 那行代码时能够通过,若是自定义类型没有实现 operator< 成员函数时,编译会出现错误。

四  member template 成员模板

成员模板也是一种函数模板,只不过针对的是构造函数的模板。

// base.h
class Base2
{

};

class Derive2:public Base2
{

};

class Base3
{
    
};

class Derive3:public Base3
{
    
};

// my_pair.h
template<typename T1, typename T2>
class MyPair
{
public:
    typedef T1 firstArgumentType;
    typedef T1 secondArgumentType;

    MyPair():first(T1()), second(T2())
    {
    }

    MyPair(const T1& arg1, const T2& arg2):first(arg1), second(arg2)
    {
    }

    // 成员模板
    template<typename U1, typename U2>
    MyPair(const MyPair<U1, U2>& other):first(other.first),second(other.second)
    {
    }
public:
    T1 first;
    T2 second;
};

// main.cpp
#include"my_pair.h"
#include"base.h"

int main()
{
    MyPair<Base2, Base3> pair1;
    MyPair<Derive2, Derive3> pair2;

    MyPair<Base2, Base3> pair3(pair2);

   return 0;
}

五  模板特化(specialization)与偏特化(partial specialization)

1. 模板特化 (specialization)

      模板特化指得是将模板类或者模板函数特化到某些特定的指定类型,使得在编译器编译时,实际编译执行的代码是特化后的版本。

 

// my_hash.h
#include<iostream>
#include<iostream>

template <class T>
struct my_hash
{
    T operator()(T x)
    {
        std::cout << "template <class T> struct my_hash" << std::endl;
        return x;
    }
};

// 以下为三个特化版本
template<>
struct my_hash<int>
{
    int operator()(int x)
    {
        std::cout << "template <> struct my_hash<int>" << std::endl;
        return x;
    }
};

template<>
struct my_hash<char>
{
    char operator()(char x)
    {
        std::cout << "template <> struct my_hash<char>" << std::endl;
        return x;
    }
};

template<>
struct my_hash<long>
{
    long operator()(long x)
    {
        std::cout << "template <> struct my_hash<long>" << std::endl;
        return x;
    }
};
// main.cpp

#include"my_hash.h"

int main()
{
    std::cout << my_hash<std::string>()("abcd") << std::endl;

    std::cout << my_hash<char>()('a') << std::endl;
    std::cout << my_hash<int>()(66) << std::endl;
    std::cout << my_hash<long>()(6666) << std::endl;

    return 0;
}

 输出:

2. 模板偏特化(partial specialization)

2.1  个数偏特化

      模板的个数变化时的特化版本

// my_vector.h
#include<iostream>

template<typename T, typename Alloc>
class my_vector
{
public:
    my_vector()
    {
        std::cout << "template<typename T, typename Alloc> class my_vector" << std::endl;
    }
};

template<typename Alloc>
class my_vector<bool, Alloc>
{
public:
    my_vector()
    {
        std::cout << "template<typename Alloc> class my_vector<bool, Alloc>" << std::endl;
    }
};

// main.cpp
#include"my_vector.h"

int main()
{
   my_vector<std::string, std::allocator<std::string>>  vec1;
   my_vector<bool, std::allocator<std::string>>  vec2;

   return 0;
}

输出:

2.2 范围偏特化

      通过特化模板类型的指针来实现指针的特化

// e.h
#include<iostream>

template<typename T>
class E
{
public:
    E()
    {
        std::cout << "template<typename T> class E" << std::endl;
    }
};

template<typename T>
class E<T*>
{
public:
    E()
    {
        std::cout << "template<typename T> class E<T*>" << std::endl;
    }
};

// main.cpp
#include"e.h"

int main()
{
    E<std::string> e1;
    E<std::string*> e2;
    
    return 0;
}

输出:

六  模板模板参数(template template parameter)

模板模板参数其实就是模板的其中参数又是另外一个模板参数,示例代码如下:

XCLS 类 的第一个模板参数是 T ,第二个模板参数是一个模板类 Container,我们可以定义一个 XX 模板类来组合使用 XCLS ,将 XX 传入即可;

也可以使用容器类 list  传入,但是如果直接传入编译是会出错的,比如下面

   XCLS<std::string, std::list> xcls3; 编译不过

  编译不过的原因是,std::list 实际上是两个模板参数,编译器检查时发现少给了一个模板参数 _Alloc ,所以编译不过。 

template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
    class list;

可以通过如下定义 Lst 来将模板类 list 的模板参数限定为 一个

template<typename T>
using Lst = std::list<T, std::allocator<T>>;
// xcls.h
#include<iostream>

template<typename T, template<typename U> class Container>
class XCLS
{
public:
    XCLS()
    {
        std::cout << "template<typename T, template<typename U> class Container> class XCLS" << std::endl;
    }
private:
    Container<T> c;
};

template<typename T>
class XX
{
public:
    XX()
    {
        std::cout << "template<typename T> class XX" << std::endl;
    }
};

// main.cpp
#include"xcls.h"

int main()
{  
   // 模板模板的参数使用
   XCLS<std::string, XX> xcls1;
   XCLS<std::string, Lst> xcls2;
   // XCLS<std::string, std::list> xcls3; 编译不过

   return 0;
}

输出:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/248386.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023.12.13 关于 MySQL 复杂查询

目录 聚合查询 聚合函数 group by 子句 执行流程图 联合查询 笛卡尔积 内连接 外连接 左外连接 右外连接 自连接 子查询 单行子查询 多行子查询 EXISTS 关键字 合并查询 union on 和 union 的区别 聚合查询 聚合函数 函数说明COUNT([DISTINCT] expr)返回查询到…

ClickHouse Kafka 引擎教程

如果您刚开始并且第一次设置 Kafka 和 ClickHouse 需要帮助怎么办&#xff1f;这篇文章也许会提供下帮助。 我们将通过一个端到端示例&#xff0c;使用 Kafka 引擎将数据从 Kafka 主题加载到 ClickHouse 表中。我们还将展示如何重置偏移量和重新加载数据&#xff0c;以及如何更…

数据库和数据仓库的区别

数据仓库是在数据库已知大量存在的前提下&#xff0c;为了进一步挖掘数据资源&#xff0c;为了决策需要产生的&#xff1b;数据仓库在设计的时候有意添加反范式设计&#xff0c;目的是提高查询效率 对比内容数据库数据仓库数据内容近期值历史的 归档的数据数据目标面向业务操作…

【数学建模】《实战数学建模:例题与讲解》第十三讲-相关分析(含Matlab代码)

【数学建模】《实战数学建模&#xff1a;例题与讲解》第十三讲-相关分析&#xff08;含Matlab代码&#xff09; 基本概念典型相关分析综合评价模型对应分析因子分析聚类分析 习题10.41. 题目要求2.解题过程3.程序 习题10.51. 题目要求2.解题过程3.程序 习题10.6&#xff08;1&a…

[原创][R语言]股票分析实战:周级别涨幅趋势的相关性

[简介]常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、De…

SQL Server数据库使用T-SQL语句简单填充

文章目录 操作步骤&#xff1a;1.新建数据库起名RGB2.新建表起名rgb3.添加三个列名4.点击新建查询5.填入以下T-SQL语句&#xff0c;点击执行&#xff08;F5&#xff09;6.刷新之后&#xff0c;查看数据 操作环境&#xff1a; win10 Microsoft SQL Server Management Studio 20…

Leetcode—237.删除链表中的节点【中等】

2023每日刷题&#xff08;六十&#xff09; Leetcode—237.删除链表中的节点 偷天换日实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { pub…

动态内存管理,malloc和calloc以及realloc函数用法

目录 一.malloc函数的介绍 malloc的用法 举个例子 注意点 浅谈数据结构里的动态分配空间 二.calloc函数的介绍 三.realloc函数的介绍 四.柔性数组的介绍 为什么有些时候动态内存函数头文件是malloc.h,有些时候却是stdlib.h 一.malloc函数的介绍 malloc其实就是动态开辟…

npm ,yarn 更换使用国内镜像源,阿里源,清华大学源

在平时开发当中&#xff0c;我们经常会使用 Npm&#xff0c;yarn 来构建 web 项目。但是npm默认的源的服务器是在国外的&#xff0c;如果没有梯子的话。会感觉特别特别慢&#xff0c;所以&#xff0c;使用国内的源是非常有必要的。 在这里插入图片描述 Nnpm&#xff0c; yarn …

[极客大挑战 2019]BuyFlag1

打开网站&#xff1a; 右上角有个菜单 (menu) &#xff0c;先点一下&#xff0c;然后就进入了 pay.php 页面。 其中关键信息如下&#xff1a; ## FlagFlag need your 100000000 money### attentionIf you want to buy the FLAG:You must be a student from CUIT!!!You must…

云端赋能大湾区:华为云照亮数字化转型之路

编辑&#xff1a;阿冒 设计&#xff1a;沐由 在中国的经济版图上&#xff0c;大湾区是极其重要的增长引擎。这块富有活力和创新力的经济区域里&#xff0c;荟聚了大量的高新技术企业&#xff0c;以及一批创新孵化器和科研机构&#xff0c;产业升级和技术创新的氛围格外浓烈。 1…

「Verilog学习笔记」单端口RAM

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1nsmodule RAM_1port(input clk,input rst,input enb,input [6:0]addr,input [3:0]w_data,output wire [3:0]r_data ); //*************code***********//re…

python实现websocket上传音频并测试

WebSocket是一种全双工通信协议&#xff0c;允许在单个TCP连接上进行双向通信。WebSocket协议允许服务器通过将请求头Upgrade设置为WebSocket来升级HTTP连接。这使得WebSocket协议可以在浏览器和服务器之间建立持久连接&#xff0c;能够实现实时数据传输和通信。 WebSocket协议…

C++STL中string详解(零基础/小白,字符串)

目录 1. 基本概念&#xff1a; 1.1 本质&#xff1a; 1.2 string和char*区别&#xff1a; 1.3 特点&#xff1a; 2. 构造函数(初始化) 3. 赋值操作 4. 字符串拼接 5 查找 和 替换 6. 字符串比较 7. 字符存取 8. 插入和删除 9. 子串获取 1. 基本概念&#xff1a; 1.…

Pytorch从零开始实战13

Pytorch从零开始实战——ResNet与DenseNet探索 本系列来源于365天深度学习训练营 原作者K同学 文章目录 Pytorch从零开始实战——ResNet与DenseNet探索环境准备数据集模型选择开始训练可视化总结 环境准备 本文基于Jupyter notebook&#xff0c;使用Python3.8&#xff0c;P…

搭建你的知识付费小程序平台:源码解析与技术实现

知识付费小程序平台在当今数字化时代扮演着越来越重要的角色&#xff0c;为教育者和学习者提供了一个灵活、便捷的学习环境。本文将以关键词“知识付费小程序源码”为基础&#xff0c;探讨如何搭建一个功能强大的知识付费小程序平台&#xff0c;并提供一些基础的技术代码示例。…

iClient3D 图元操作

1. S3MTilesLayer&#xff0c;S3M(Spatial 3D Model)图层类 S3MTilesLayer&#xff0c;S3M(Spatial 3D Model)图层类&#xff0c;通过该图层实现加载三维切片缓存&#xff0c;包括倾斜摄影模型、BIM模型、点云数据、精细模型、矢量数据、符号等。 那S3MTilesLayer中针对图元的…

vue2 tailwindcss jit模式下热更新失效

按照网上教程安装的tailwindcss&#xff0c;但是修改类名后热更新的时候样式没有生效&#xff0c;参考了大佬的文章&#xff0c;解决了该问题。 安装cross-env 修改前 "dev": " vue-cli-service serve", 修改后 "dev": "cross-env TAILWIN…

MYSQl基础操作命令合集与详解

MySQL入门 先来个总结 SQL语言分类 DDL&#xff08;Data Definition Language&#xff09; - 数据定义语言: 用于定义和管理数据库结构&#xff0c;包括创建、修改和删除数据库对象。 示例&#xff1a;CREATE, ALTER, DROP等语句。 DML&#xff08;Data Manipulation Lan…

Axios入门案例——后端学习

目录 后端准备 导入依赖 解决跨域 User实体类 DemoController测试接口 前端准备 项目结构 axios.js axios.html 开始测试 后端结果 前端结果 后端准备 导入依赖 案例会用到以下的三个依赖。 <dependency><groupId>org.springframework.boot</gro…