16 c++ 模板与泛型编程

16、深入理解C++模板与泛型编程 本文深入探讨了C++模板与泛型编程的核心概念,包括函数模板、类模板的基本用法,模板特化与元编程的应用,以及模板与其他面向对象特性的关系。同时,文章还对比了C++模板与其他语言的泛型机制,并结合设计模式、性能优化、库设计及现代C++特性(如Concepts和变参数模板)进行了详细分析,帮助读者更好地理解和应用C++模板技术。 阅读详情
#ifndef Color_H
#define Color_H

#include <string>
#include <type_traits>
#include <utility>

class Color{
private:
    std::string _value;

public:
    Color(std::string value):_value(value){};

    std::string getValue() const{ return _value; }
};

// 函数模板
// TColor 为模板参数名称,TColor 可以时任意类型,但必须实现 getValue,否则在编译时报错
// 多个模板参数 template<typename TColor, typename TColor1>
template<typename TColor>
bool IsEqualOfColor(TColor leftColor, TColor rightColor)
{
    return leftColor.getValue() == rightColor.getValue();
}

// 非类型模板参数
// 非类型模板参数表示一个值,由编译器推断的值代替该参数
// 这里将list声明为引用,因为我们无法拷贝一个数组
template<int TSize>
int GetSize(const int (&list)[TSize]){
    return TSize;
}

// 通过尾置返回,我们可以指定返回类型
// 这里返回类型是 string
template<typename T>
auto GetColorValue(T color) -> decltype(color.getValue());

// 这种情况下,传给f1的实参必须时左值
template<typename T>
void f1(T &t){};

// 这种情况下,传给f2的实参可以是左值,也可以是右值
// 如 f2(5) 时,5可以被绑定到 const int & 上,所以 T 被推断为 int
// 以下代码没毛病:
// const int &t = 5;
// int &&b = 5; const int &c = b;
template<typename T>
void f2(const T &t){};

// 这种情况下,传给f3的实参即可以时左值,也可以是右值
// 当 t 为 20 时,T 的被推断为 int,(int &&t = 20 ,没毛病)
// 当 f3(a) a 为 int 时,问题出现了(int a = 1; int &&t = a;),左值无法赋值给右值
// 当出现这种情况时,有两个例外规则
// 例外1:
// 当 t 为 int a 时,此时编译器推断 T 为 int&,则 t 的类型为 int& &&
// 当 t 为 int &&b 时,此时编译器推断 T 为 int&&,则 t 的类型为 int&& &&
// 例外2:
// T& &, T& &&, T&& & 类型将被折叠成 T&
// T&& &&,将被折叠成 T&&
// 这两个例外规则暗示我们可以将任何类型传给 T&& 模板类型参数
template<typename T>
void f3(T &&t){};

// 类型转换
// 针对类型的操作
template<typename T>
void TypeConvert(T &&t){
    // 移除T的引用类型
    // 如:T为int& 或 int&&,则typename remove_reference<T>::type返回int
    // 则下面的代码为 int & a;
    typename std::remove_reference<T>::type & a;
}

// 关于move标准库函数原理
template<typename T>
typename std::remove_reference<T>::type&& move(T&& t){
    return static_cast<typename std::remove_reference<T>::type&&>(t);
}

// 使用forward保持类型信息(#include <utility>)
// forward返回给的类型的右值引用
template<typename T>
void f4(T &&t){
    // f4(5)时,T为int,则std::forward<T>(t)返回 t 的类型为 int&&
    // f4(int)时,T为int&,则std::forward<T>(t)返回 t 的类型为 int& &&
    // f4(int&&)时,T为int&&,则std::forward<T>(t)返回 t 的类型为 int&& &&
    f3(std::forward<T>(t));
};

// 可变参数模板
template<typename T>
void f5(T t){
}

template<typename T, typename... Args>
void f5(T t, Args ... args){
    sizeof...(args);    // 返回参数包参数的数量

    // ...为扩展动作,此动作会将参数和类型进行扩展
    // 例如:
    // f5(4, "a", 'b')
    // 那么 t 为 4, args 为 { "a", 'b' }
    // f5(args...)后代码为 f5("a", 'b')
    // 这会调用 void f5(T t, Args ... args)
    // 那么 t 为 "a", args 为 { 'b' }
    // f5(args...)后代码为 f5('b')
    // 这会调用 void f5(T t)
    f5(args...);

    // 如果 f5(1, 1.1)
    // 执行 f6(forward<Args>(args)...) 
    // 那么 f6(forward<int>(1), forward<double>(1.1))
}

#endif


#ifndef Pan_H
#define Pan_H
#include <iostream>
#include <string>
#include "./Color.h"

// SetColor1作为友元时,必须进行声明
template <typename>
void SetColor1();

// 模板的头文件通常即包含声明,也包含定义
// 类模板
// 编译器不能为类模板推断模板参数类型
//  = Color 为指定默认实参
template <typename TColor = Color>
class Pan
{
    // 只应用于特定类型的友元
    // 例如SetColor1<Color>只能应用于Pan<Color>
    // 注意:这是一个模板实例,所以必须有前置声明
    friend void SetColor1<TColor>();

    // 能应用于所有类型的友元
    friend void SetColor2();

    // 友元模板声明
    // SetColor3的所有实例都是Pan模板的友元
    template <typename X>
    friend void SetColor3();

private:
    TColor _color;

public:
    Pan() = default;
    Pan(TColor color) : _color(color){};

    TColor GetColor() const;

    // 对于给定的模板参数类型,都只有一个Instance,不同模板参数类型的 Instance 不同
    // 例:TColor 为 Color 的类型只有一个 Instance
    static int Instance;

    // 成员模板
    // 成员模板可以自定义函数的模板参数
    template <typename T>
    void SetMoney(T t, TColor color);
};

// 类外定义模板成员
template <typename TColor>
TColor Pan<TColor>::GetColor() const
{
    return _color;
}

// 特例化成员函数
// 特例化可以应用于类或函数上
// 通过 template <> 来声明一个特例化实例
// 当 TColor 为 Color 将使用下面的函数而不是模板函数
template <>
Color Pan<Color>::GetColor() const
{
    return _color;
}

// 部分特例化
// 部分特例化只能应用于类
// 当TColor是引用类型时将使用下面的模板
template <typename TColor>
class Pan<TColor&>{
};

// 在类外定义成员模板时必须指定类模板参数类型
template <typename TColor>
template <typename T>
void Pan<TColor>::SetMoney(T t, TColor color)
{
}

#endif
#include <iostream>
#include <vector>
#include <type_traits>
#include "Color.h"
#include "Pan.h"

using namespace std;

// 为类模板定义别名
// 定义各个 模板 APan,类型是 Pan<T>
template<typename T> using APan = Pan<T>;

// 我们每使用一个 IsEqualOfColor<string> ,编译器就会帮我们实例一个,
// 使用 extern template 声明一个实例,编译器便不会帮我们生成这个实例,但必须确保在使用之前该模板类型被实例
extern template bool IsEqualOfColor<string>(string, string);

int main()
{
    Color color1("#fff");
    Color color2("#fff");
    // 使用模板函数
    // 当我们指定一个TColor的类型时,编译器就会为我们生成一个对应的函数
    // 例如:TColor为Color,则编译器为我们生成
    // bool IsEqualOfColor(Color leftColor, Color rightColor)函数
    // 而我们在 IsEqualOfColor 中用到的 getValue 方法,如果 Color 未定义改方法,则编译会报错
    if(IsEqualOfColor<Color>(color1, color2)){
        cout << "equal" << endl;
    }

    // 类模板对象
    Color color3("#fff");
    Pan<Color> pan1(color3);

    // 默认情况下,模板的成员函数只有在用到时,编译器才会去实例成员函数的一个对应类型
    // 这一特性告诉我们,我们指定的模板参数不需要完全符合我们类的需求,只要符合我们调用的成员函数的需求即可
    Color color4 = pan1.GetColor();

    // 使用默认模板实参
    Pan<> pan2();

    cout << "enter key" << endl;
    cin.get();

    return 0;
}

// 类型推断
void TypeInfer(){
    Color color1("#fff");
    Color color2("#fff");

    // 不指定模板参数也可以,编译器会使用实参的类型进行推断
    // 编译器可以从参数类型推断模板参数类型,但无法从返回类型推断模板参数类型
    // 如果IsEqualOfColor的返回类型是TResult,则必须显示指定TResult的类型
    if(IsEqualOfColor(color1, color2)){
        cout << "equal" << endl;
    }

    // 当我们用函数模板初始化一个函数指针时,模板参数类型从函数指针推断
    bool (*funp)(Color, Color) = IsEqualOfColor;

    // list 的数量为2,所以编译器推断 TSize 为 2
    int list[] = {1, 3};
    cout << GetSize(list) << endl;      // 输出2
}
从宁德新能源面试官视角,拆解Halcon/OpenCV图像处理工程师的硬核技能树(附避坑指南) 本文从宁德新能源面试官视角出发,详细拆解Halcon/OpenCV图像处理工程师的核心技能树,涵盖硬件选型、算法实现和系统工程思维三大能力维度。文章提供工业视觉工程师面试的实战避坑指南,包括硬件配置要点、算法优化技巧及职业发展路径,助力求职者系统提升图像处理专业技能。 阅读详情

相关推荐

实战解析:在.NET中实现Dify API流式请求与响应的完整方案

本文详细解析了在.NET应用中对接Dify API时实现流式请求与响应的完整方案。针对传统后端“接收完才返回”的痛点,文章提供了基于ASP.NET Core的实战代码,通过配置HttpCompletionOption.ResponseHeadersRead和手动Flush响应流,构建高效的中转管道,确保AI回复能够像ChatGPT一样实时逐字推送到前端,显著提升用户体验。

weixin_29267307的博客 296

【c++ primer 笔记】第 16章 模板与泛型编程

模板定义以关键字 template 开始,后跟一个用 包围,用逗号分隔的模板参数列表。在模板定义中,模板参数列表不能为空模板参数列表类似函数列表,需要在类或函数定义中用到的类型和值。使用模板时,需要指定模板实参,将其绑定到模板参数上。'普通函数' int compare(const string & v1 , const string & v2) {return 0;

小呆鸟blog 2046

新手入门:N-CMAPSS数据集解析与实战指南

本文详细解析了N-CMAPSS数据集的结构与应用,为新手提供航空发动机故障预测的实战指南。通过Python代码示例展示数据加载、探索和特征工程技巧,帮助读者快速掌握剩余寿命(RUL)预测的关键步骤,并分享常见问题解决方案与进阶学习路径。

weixin_29056701的博客 377

Atmosphere 定制固件适配 19.0 必做的 5 件事

如果你的 Switch 已经升到 19.0 系统,而 SD 卡里的定制固件还停在旧版 Atmosphere,接下来大概率会遇到卡 logo、黑屏,甚至直接弹出 fatal 错误。这篇帖子讲清 Atmosphere 适配 19.0 的完整流程:该用哪个版本、文件怎么替换、出问题怎么自救,全程只需要动手做五件事。 [![Atmosphere 适配 19.0 固件后的启动画面](https://raw

gitblog_00529的博客 317

Dify视觉模型节点避坑指南:我用Qwen2.5-VL做OCR识别时踩过的3个坑(及解决方案)

本文分享了使用Dify平台和Qwen2.5-VL视觉模型进行OCR票据识别时遇到的三个常见问题及解决方案,包括文件变量传递、结构化输出和条件分支判断失效。通过实战经验,帮助开发者优化多模态模型在财务自动化中的应用,提升OCR识别精度和效率。

weixin_29284885的博客 406

渗透测试面试题

渗透测试面试题 一.思路流程 1.信息收集 服务器的相关信息(真实ip,系统类型,版本,开放端口,WAF等) 网站指纹识别(包括,cms,cdn,证书等),dns记录 whois信息,姓名,备案,邮箱,电话反查(邮箱丢社工库,社工准备等) 子域名收集,旁站,C段等 google hacking针对化搜索,pdf文件,中间件版本,弱口令扫描等 扫描网站目录结构,爆后台,网站banner,测试文件,...

千寻的博客 12万+

《c++ primer》 第16章 模板与泛型编程

面向对象编程和泛型编程都能处理编写程序时不知道类型的情况 区别就是OOP是在运行时处理,而泛型编程是在编译的时候就能知道类型了 一.定义模板 1.我们可以为函数定义一个模板,而不是为每一个类型定义一个函数。 比较函数: #include template int compare(const T&v1, const T&v2) { if(v1 < v2)

IT小小鸟~~ 3122

电机驱动和电源等大电流设计中的并联 MOSFET设计

在电机驱动等应用中,半桥拓扑(通常为 3 相)用于生成在电机中产生正扭矩或负扭矩的交流电源信号。想要更高的输出电流能力,只有通过并联形成每个功能开关的 MOSFET,才能实现高输出电流。当多个功率 MOSFET 并联以增加系统整体电流能力容量时,通常假设电流在并联器件之间均等分配或均等共享。然而,在并联 MOSFET 时,需要考虑并联器件之间的电流分配。PCB 布局的若干特性和特定的MOSFET 参数会影响这种分配,并在参数不匹配或布局不对称时导致均流不平衡。

小幽余生不加糖 2487

第16章 模板和泛型编程【C++】

已经学习了标准容器,我们就会产生好奇,为什么它可以存储任意类型呢?向自定义的函数的形参与实参都是有着严格的类型匹配,面向对象编程和泛型编程都能处理在编写程序时不知道类型的情况,不同之处在于,OOP能处理类型在程序运行之前都未知的情况,而泛型编程中,在编译时就能获知类型了,在OOP总我们知道利用虚函数与动态绑定机制可以做到有时某种算法的代码实现是相同的,只有变量类型不同,如下面的情况 泛型编程就是为解决这种问题而生的函数模板就是一个公式,可以来生成针对特定类型的函数版本 编译器生成的版本通常被称为模板的实例

高万禄的博客 563

AI技术在电商中的实际应用

人工智能、电商、推荐系统、个性化、机器学习、深度学习 1. 背景介绍 电子商务行业近年来发展迅速,用户数量不断增长,商品种类日益丰富。然而,随着市场竞争的加剧,电商平台面临着如何提升用户体验、提高转化率、挖掘潜在商机等一系列挑战。人工智能(AI)技术作为一种新兴技术,凭借其强大的数

AGI×大数据,开启智能时代的认知跃迁;解码AGI,赋能数据驱动的智能革命。 1741

Algorithm:【算法进阶之路】之算法面试刷题集合—数据结构的简介、最强学习路线(逻辑结构【数组-链表-栈和队列/树-图-哈希】、物理结构【元素/关系】、数据运算【十大排序/四大查找-图三大搜索-

​ Algorithm:【算法进阶之路】之算法面试刷题集合—数据结构的简介、最强学习路线(逻辑结构【数组-链表-栈和队列/树-图-哈希】、物理结构【元素/关系】、数据运算【十大排序/四大查找-图三大搜索-树三大遍历】、高级算法【枚举/回溯/递归/分治/动规/贪心】)、问题为导向的十大类刷题算法总结之详细攻略 目录 相关文章 数据结构思维导图 基本术语 一、数据结构的概述 二、数据的逻辑结构 三、数据的物理结构 四、数据的运算

头部AI社区如有邀博主AI主题演讲请私信—心比天高,仗剑走天涯,保持热爱,奔赴向梦想!低调,专注,谦虚,自律,反思,成长,还算比较正能量的博主,公益免费传播…内心特别想在AI界做出一些可以推进历史进程影响力的技术(兴趣使然,有点小情怀,也有点使命感呀 6849

16 C++ 模板与泛型编程

模板是C++中泛型编程的基础。一个模板就是一个创建类或函数的蓝图或公式。当使用一个vector这个样的泛型类型,或find这样的泛型函数时,我们提供足够的星系,将蓝图转换为特定的类或函数。这种转换发生在编译时。function template    模板参数列表template parameter list   模板参数template parameter   模板实参template argument 非类型模板参数 nontype parameter inline和constexpr 类模板 实

surfaceyan的博客 773

Vue3 - 实现用户上传本地视频文件到服务器+上传进度条+暂停续传+中断取消上传等,视频上传后可在线播放预览已上传的视频,视频文件上传视频回显示例代码(支持Element、Antd等upload组件

实现视频上传和视频预览,vue3实现视频上传功能,上传视频回显,视频流上传播放功能,vue与axios上传视频并显示上传进度,upload组件实现视频文件上传视频回显,upload组件实现视频上传及进度条展示,视频上传及实时进度条显示,视频上传过程中如何中断上传,VUE3+element 上传视频,大文件分片上传+断点续传,axios大文件切片上传,Vue3上传视频后如何播放预览,上传本地视频到后端服务器及在线预览播放视频+移除视频+进度条上传,将已选视频上传服务端并可预览视频,详细实现选择视频并上传到服务

🏆 前端领域优质创作者 3116

C++ Primer 第16章 模板与泛型编程 学习笔记

近期不是很需要这章的内容,写的非常非常粗糙,以后会补充。好好学习天天向上。

a20180825的博客 4338

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

《C++ Primer》 第四版 第16章 模板与泛型编程

《C++ Primer》 第四版 第16章 模板与泛型编程 思维导图笔记 超级详细,非常详细,图片版,有利于复习查看

onlyshi的专栏 683

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【经典书籍】C++ Primer 第16章模板与泛型编程精华讲解

模板,就是教你写一份“通用蓝图”,让编译器帮你自动为不同类型生成具体代码!“我要造一把刀,但这把刀不固定是水果刀、菜刀还是匕首,而是‘任意刀’,你给我啥材料,我给你削啥!老 G 对小 T 说:模板不是魔法,而是一种编程思想 —— 泛型编程(Generic Programming)。你写的不是针对某个具体类型的代码,而是**针对‘任意类型’的逻辑。只要类型满足你的要求(比如有 + 操作、有 << 操作),你的代码就能运行!只要你的类重载了<<运算符,小 T 的通用打印函数模板就能打印它!

chenningpocom的博客 1238

16. C++泛型编程(函数模板)

C++中如何交换两个变量的值? 你注意到了么?除了类型不同,函数体代码完全相同!!! C++强调代码复用!那如何解决这个代码冗余的问题呢? 泛型编程 泛型编程的概念:不考虑具体数据类型的编程模式。 C++中,泛型编程是通过函数模板。1. 函数模板是一种特殊的函数可用不同类型进行调用;2. 函数模板看起来和普通函数很相似,区别是类型可被参数化; 函数模板的语法规则 ...

zhubao124的博客 1275

《C++ Primer》导学系列:第 16 章 - 模板与泛型编程

在C++中,模板是一种强大的工具,可以让我们编写通用代码,而不必在编译时指定类型。模板允许我们定义函数模板和类模板,使得相同的代码可以处理不同的数据类型。理解模板的基本概念和语法是掌握高级C++编程的重要一步。类模板允许我们定义一个可以接受任意类型数据成员的类。public:private:本节总结了解了模板的基本概念和语法,掌握了函数模板和类模板的定义方法。理解了模板参数的使用,包括类型参数、非类型参数和模板模板参数。掌握了模板实例化的概念和方法,能够正确实例化函数模板和类模板。

iShare_Carlos的博客 1517

掌握C++模板编程:Cpp-Primer-5th-Exercises第16章实战指南

C++模板编程是C++ Primer第5版第16章的核心内容,也是提升C++编程能力的关键技能。通过Cpp-Primer-5th-Exercises项目中的实战练习,你将系统掌握模板类、函数模板、模板特化等核心概念,轻松应对复杂的泛型编程挑战。 ## 为什么模板编程是C++开发者的必备技能 🚀 模板是C++实现泛型编程的基础,它允许你编写与类型无关的代码,大幅提高代码复用性和灵活性。在标准库

gitblog_00320的博客 936

模板与泛型编程 c++ primer ch16.1

在摸板定义中,模板参数列表不能为空, 编译器用推断出的参数来进行 实例化(instantiation) 一般来说 模板是有type parameter 但是也可以声明 nontype parameter template<unsgned N,unsigned M> int compare(const char(&p) [n], const char(&p2)[M]){ ...

weixin_30540691的博客 968

【C++ Primer】第16章 模板与泛型编程 (1)

模板是C++泛型编程的基础。介绍函数模板与类模板。

HPP_优快云的博客 471

C++ Primer 第五版 第16章 模板与泛型编程

一个函数模板(function template)就是一个公式,可用来生成针对特定类型的函数版本。模板定义以关键字template开始,后跟一个模板参数列表(template parameter list),这是一个逗号分隔的一个或多个模板参数的列表,用小于号(<)和大于号(>)包围起来。在模板定义中,模板参数列表不能为空。模板参数表示在类或函数定义中用到的类型或值。当使用模板时,我们(隐式地或显式地)指定模板实参(template argument),将其绑定到模板参数上。

weixin_44500921的博客 1235

C++ Primer第五版之第16章 模板与泛型编程

第16章 模板与泛型编程 定义模板 函数模板 模板定义以关键字template开始,后跟一个模板参数列表(是一个逗号分隔的一个或多个模板参数的列表),用<>包围起来。 在模板定义中,模板参数列表不能为空。 template <typename T> int compare(const T &v1, const T &v2) { if (v1...

HakunaMatata的博客 397

C++Primer 笔记之----第16章 模板与泛型编程

引子: 在C++中,模板是泛型编程的基础,是创建类或函数的公式,比如说vector 16.1 模板定义 1、定义函数模板 template //模板形参表,可以是多个,用,号隔开 inline int compare(const T &v1,const T &v2)//inline必须放在返回类型之前,当然也可以不设置为内联函数 { if(v1>v2)return 1; if(

hang on it more longer 241

c++第16章 模板与泛型编程(一)

模板与泛型编程 函数模板 我们可以定义一个通用的函数模板(function tempalte),而不是为每个类型都定义一个新函数。一个函数模板就是一个公式,可以用来生成针对类型的函数版本,例如以下的compare函数: template <typename T> int compare(const T &v1,const T &v2) { if(v1 &...

加油啊少年的博客 200

《c++ primer》第16章 模板与泛型编程

泛型编程就是独立于任何特定类型的方式进行编码。模板是泛型编程的基础。使用模板无需了解模板的定义。依赖于编译时的多态性或参数式多态性 模板的定义 函数模板定义template int compare(const T &v1,const T &v2) { if(v1<v2) return -1; if(v2>v1) return 1; return 0

skyFuhrer的专栏 928

C++ Primer 笔记16. 模板与泛型编程

定义模板 函数模板:编译器根据实参类型实例化特定版本的函数 模板参数列表: 非类型模板参数:表示一个值 类模板:代替用户需要提供的类型或值 友元与类模板: 别名: static函数: 每个实例都有自己的static成员实例 必须通过引用特定的实例来访问static成员 当名字表示类型时,必须用关键字typename显示标注 本身是模板的成员函数不能是虚函数 默认模板实参: 控制实例化: 避免多个文件中实例化相同...

I_ren的博客 232
上一篇: 15 c++ 面向对象设计
下一篇: 17 c++ 标准库特殊设施
dabusidede
博客等级 码龄9年 84粉丝 208原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值