C++模板基础(五)

2023-10-27

函数模板
● 函数模板的 ( 完全 ) 特化: template<> void f(int) / template<> void f(int)
– 并不引入新的(同名)名称,只是为某个模板针对特定模板实参提供优化算法

函数模板的特化本质上是实例化,有时实例化和特化会混用,但是函数模板的实例化是引入一个实例,而函数模板特化是为某些模板参数引入特别的实现。

– 注意与重载的区别
函数模板的重载

template<typename T>
void fun(T x)
{
    //std::cout << x << std::endl;
}

template<typename T>
void fun(T* x)
{
    //std::cout << x << std::endl;
}

函数模板的特化

template<typename T>
void fun(T* x)
{
    //std::cout << x << std::endl;
}

template<>
void fun(int* x)
{
    //std::cout << x << std::endl;
}

– 注意特化过程中的模板形参推导
● 避免使用函数模板的特化(Calling Functions : A Tutorial
在这里插入图片描述

template<typename T>
void fun(T x) //#1
{
    std::cout << "template<typename T> void fun(T x)" << std::endl;
}

template<typename T>
void fun(T* x) //#2
{
    std::cout << "template<typename T> void fun(T* x)" << std::endl;
}

template<>
void fun(int* x) //同template<> void fun<int>(int* x),是#2函数模板的特化
{
    std::cout << "template<> void fun(int* x)" << std::endl;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun(&x);

    return a.exec();
}

在这里插入图片描述

template<typename T>
void fun(T x) //#1
{
    std::cout << "template<typename T> void fun(T x)" << std::endl;
}

template<typename T>
void fun(T* x) //#2
{
    std::cout << "template<typename T> void fun(T* x)" << std::endl;
}

template<>
void fun<int*>(int* x) //是#1函数模板的特化
{
    std::cout << "template<> void fun<int*>(int* x)" << std::endl;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun(&x); //调用#2函数模板产生的实例化的版本

    return a.exec();
}

在这里插入图片描述

template<typename T>
void fun(T x) //#1
{
    std::cout << "template<typename T> void fun(T x)" << std::endl;
}

template<>
void fun(int* x) //注意这个特化放在#1函数模板的后面,所以它是#1函数模板的特化
{
    std::cout << "template<> void fun(int* x)" << std::endl;
}

template<typename T>
void fun(T* x) //#2
{
    std::cout << "template<typename T> void fun(T* x)" << std::endl;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun(&x); //调用#2函数模板的一个实例化版本

    return a.exec();
}

在这里插入图片描述

– 不参与重载解析,会产生反直觉的效果
– 通常可以用重载代替

template<typename T>
void fun(T x)
{
    std::cout << "template<typename T> void fun(T x)" << std::endl;
}

void fun(int* x) //参与了重载解析,引入了新的名称,这种情况下fun函数有三个版本
{
    std::cout << "void fun(int* x)" << std::endl;
}

template<typename T>
void fun(T* x)
{
    std::cout << "template<typename T> void fun(T* x)" << std::endl;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun(&x); //调用void fun(int* x)

    return a.exec();
}
template<typename T>
void fun(T x)
{
    std::cout << "template<typename T> void fun(T x)" << std::endl;
}

template<typename T>
void fun(T* x)
{
    std::cout << "template<typename T> void fun(T* x)" << std::endl;
}

void fun(int* x) //参与了重载解析,引入了新的名称,这种情况下fun函数有三个版本
{
    std::cout << "void fun(int* x)" << std::endl;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun(&x); //调用void fun(int* x)

    return a.exec();
}

在这里插入图片描述

– 一些不便于重载的情况:无法建立模板形参与函数形参的关联

template<typename T, typename Res>
Res fun(T x)
{
    std::cout << "template<typename T, typename Res> Res fun(T x)" << std::endl;
    return Res{};
}

● 使用 if constexpr 解决

#include<type_traits>
template<typename Res, typename T>
Res fun(T x)
{
    if constexpr(std::is_same_v<Res, int>)
    {
        std::cout << "1" << std::endl;
    }
    else
    {
        std::cout << "2" << std::endl;
    }
    return Res{};
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun<int>(&x); //输出1

    return a.exec();
}
#include<type_traits>
template<typename Res, typename T>
Res fun(T x)
{
    if constexpr(std::is_same_v<Res, int>)
    {
        std::cout << "1" << std::endl;
    }
    else
    {
        std::cout << "2" << std::endl;
    }
    return Res{};
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun<float>(&x); //输出2

    return a.exec();
}

● 引入“假“”函数形参

#include<type_traits>
template<typename Res, typename T>
Res fun(T x, const Res&)
{
    if constexpr(std::is_same_v<Res, int>)
    {
        std::cout << "1" << std::endl;
    }
    else
    {
        std::cout << "2" << std::endl;
    }
    return Res{};
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun(&x, float); //输出2

    return a.exec();
}
template<typename T>
int fun(T x, const int&)
{
    std::cout << "template<typename T> int fun(T x, const int&)" << std::endl;
    return int{};
}
template<typename Res, typename T>
Res fun(T x, const Res&)
{
    std::cout << "template<typename Res, typename T> Res fun(T x, const Res&)" << std::endl;
    return Res{};
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun(&x, int{});

    return a.exec();
}

在这里插入图片描述

template<typename T>
int fun(T x, const int&)
{
    std::cout << "template<typename T> int fun(T x, const int&)" << std::endl;
    return int{};
}
template<typename Res, typename T>
Res fun(T x, const Res&)
{
    std::cout << "template<typename Res, typename T> Res fun(T x, const Res&)" << std::endl;
    return Res{};
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun(&x, float{});

    return a.exec();
}

在这里插入图片描述

template<typename Res, typename T>
Res fun(T x)
{
    if constexpr(std::is_same_v<Res, int>)
    {
        std::cout << "1" << std::endl;
    }
    else
    {
        std::cout << "2" << std::endl;
    }
    return Res{};
}

template<typename T>
int fun<int, T>(T x) //不支持函数模板的这种特化,Error: Function template partial specialization is not allowed
{

}

● 通过类模板特化解决
●(C++20) 函数模板的简化形式:使用 auto 定义模板参数类型

#include<iostream>
void fun(auto x)
{
}

int main()
{
    int x;
    fun(&x);
}
//CPPInsights中的输出
#include<iostream>
void fun(auto x)
{
}

/* First instantiated from: insights.cpp:9 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void fun<int *>(int * x)
{
}
#endif


int main()
{
  int x;
  fun(&x);
  return 0;
}

#include<iostream>
void fun(auto& x)
{
}

int main()
{
    int x;
    fun(x);
}
//CPPInsights中的输出
#include<iostream>
void fun(auto& x)
{
}

/* First instantiated from: insights.cpp:9 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void fun<int>(int & x)
{
}
#endif


int main()
{
  int x;
  fun(x);
  return 0;
}

#include<iostream>
void fun(auto&& x)
{
}

int main()
{
    int x;
    fun(x);
}
//CPPInsights中的输出
#include<iostream>
void fun(auto&& x)
{
}

/* First instantiated from: insights.cpp:9 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void fun<int &>(int & x)
{
}
#endif


int main()
{
  int x;
  fun(x);
  return 0;
}

#include<iostream>
void fun(auto&& x)
{
}

int main()
{
    int x;
    fun(2);
}
//CPPInsights中的输出
#include<iostream>
void fun(auto&& x)
{
}

/* First instantiated from: insights.cpp:9 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void fun<int>(int && x)
{
}
#endif


int main()
{
  int x;
  fun(2);
  return 0;
}

– 优势:书写简捷
– 劣势:在函数内部需要间接获取参数类型信息

void fun(auto& x)
{
    decltype(x) tmp = 3;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int x;
    fun(x); //Error: cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'

    return a.exec();
}

参考
深蓝学院:C++基础与深度解析

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

C++模板基础(五) 的相关文章

  • 向进度条添加百分比文本 C#

    我有一个方法可以显示进程栏何时正在执行以及何时成功完成 我工作得很好 但我想添加一个百分比 如果完成 则显示 100 如果卡在某个地方 则显示更少 我在网上做了一些研究 但我无法适应我正在寻找的解决方案 这是我的代码 private voi
  • 未提供参数时如何指定 C# System.Commandline 行为?

    在我的控制台应用程序中 当未提供控制台参数时 将执行我指定列表 在本例中为参数 3 的任何处理程序 调用该处理程序时 布尔参数设置为 false 但对我来说 根本不调用它更有意义 如何防止这种情况发生并显示帮助文本 using System
  • 为什么 int8_t 和用户通过 cin 输入显示奇怪的结果[重复]

    这个问题在这里已经有答案了 一小段代码让我发疯 但希望你能阻止我跳出窗外 看这里 include
  • 如何将非静态类成员“std::bind”绑定到 Win32 回调函数“WNDPROC”?

    我正在尝试将非静态类成员绑定到标准WNDPROC http msdn microsoft com en us library ms633573 aspx功能 我知道我可以通过将类成员设为静态来简单地做到这一点 但是 作为一名 C 11 ST
  • 当我们想要返回对象的引用时,为什么我们在赋值运算符中返回 *this 而通常(而不是 this)?

    我正在学习 C 和指针 我以为我理解了指针 直到我看到这个 一方面 asterix 运算符是解引用的 这意味着它返回值所指向的地址中的值 而与号 运算符则相反 它返回值存储的地址记忆 现在阅读有关赋值重载的内 容 它说 我们返回 this因
  • 使用 Newtonsoft 和 C# 反序列化嵌套 JSON

    我正在尝试解析来自 Rest API 的 Json 响应 我可以获得很好的响应并创建了一些类模型 我正在使用 Newtonsoft 的 Json Net 我的响应中不断收到空值 并且不确定我的模型设置是否正确或缺少某些内容 例如 我想要获取
  • 单个对象的 Monogame XNA 变换矩阵?

    我读过一些解释 XNA Monogame 变换矩阵的教程 问题是这些矩阵应用于 SpriteBatch Begin matrix 这意味着所有 Draw 代码都将被转换 如何将变换矩阵应用于单个可绘制对象 就我而言 我想转换滚动背景 使其自
  • java.io.Serialized 在 C/C++ 中的等价物是什么?

    C C 的等价物是什么java io Serialized https docs oracle com javase 7 docs api java io Serializable html 有对序列化库的引用 用 C 序列化数据结构 ht
  • 如何使用 LINQ2SQL 连接两个不同上下文的表?

    我的应用程序中有 2 个数据上下文 不同的数据库 并且需要能够通过上下文 B 中的表的右连接来查询上下文 A 中的表 我该如何在 LINQ2SQL 中执行此操作 Why 我们正在使用 SaaS 产品来跟踪我们的时间 项目等 并希望向该产品发
  • 在 C 中初始化变量

    我知道有时如果你不初始化int 如果打印整数 您将得到一个随机数 但将所有内容初始化为零似乎有点愚蠢 我问这个问题是因为我正在评论我的 C 项目 而且我对缩进非常直接 并且它可以完全编译 90 90 谢谢 Stackoverflow 但我想
  • 我可以使用 moq Mock 来模拟类而不是接口吗?

    正在经历https github com Moq moq4 wiki Quickstart https github com Moq moq4 wiki Quickstart 我看到它 Mock 一个接口 我的遗留代码中有一个没有接口的类
  • DbContext 和 ObjectContext 有什么区别

    From MSDN 表示工作单元和存储库模式的组合 使您能够查询数据库并将更改分组在一起 然后将这些更改作为一个单元写回存储 DbContext在概念上类似于ObjectContext 我虽然DbContext只处理与数据库的连接以及针对数
  • C# HashSet 只读解决方法

    这是示例代码 static class Store private static List
  • AES 128 CBC 蒙特卡罗测试

    我正在 AES 128 CBC 上执行 MCT 如中所述http csrc nist gov groups STM cavp documents aes AESAVS pdf http csrc nist gov groups STM ca
  • “接口”类似于 boost::bind 的语义

    我希望能够将 Java 的接口语义与 C 结合起来 起初 我用过boost signal为给定事件回调显式注册的成员函数 这非常有效 但后来我发现一些函数回调池是相关的 因此将它们抽象出来并立即注册所有实例的相关回调是有意义的 但我了解到的
  • 方法优化 - C#

    我开发了一种方法 允许我通过参数传入表 字符串 列数组 字符串 和值数组 对象 然后使用这些参数创建参数化查询 虽然它工作得很好 但代码的长度以及多个 for 循环散发出一种代码味道 特别是我觉得我用来在列和值之间插入逗号的方法可以用不同的
  • 如何部署“SQL Server Express + EF”应用程序

    这是我第一次部署使用 SQL Server Express 数据库的应用程序 我首先使用实体 框架模型来联系数据库 我使用 Install Shield 创建了一个安装向导来安装应用程序 这些是我在目标计算机中安装应用程序所执行的步骤 安装
  • C++ 条件编译

    我有以下代码片段 ifdef DO LOG define log p record p else define log p endif void record char data 现在如果我打电话log hello world 在我的代码中
  • 如何从 ODBC 连接获取可用表的列表?

    在 Excel 中 我可以转到 数据 gt 导入外部数据 gt 导入数据 然后选择要使用的数据源 然后在提供登录信息后 它会给我一个表格列表 我想知道如何使用 C 以编程方式获取该列表 您正在查询什么类型的数据源 SQL 服务器 使用权 看
  • 当从finally中抛出异常时,Catch块不会被评估

    出现这个问题的原因是之前在 NET 4 0 中运行的代码在 NET 4 5 中因未处理的异常而失败 部分原因是 try finallys 如果您想了解详细信息 请阅读更多内容微软连接 https connect microsoft com

随机推荐

  • 单测mock和stub

    A variety of different terms are used to refer to these custom objects In an effort to clarify the vocabulary Gerard Mes
  • Design1.CMOS工艺OD门,传输门,三态门原理应用浅析

    纲要 OD门 传输门 三态门 1 OD门 i 概念 在CMOS电路中为了满足输出电平变换 吸收大负载电流以及实现线与连接等需要 需要将输出级电路结构改为漏极开路输出的MOS管 构成漏极开路输出 Open Drain Output 门电路 简
  • Android中的Selector的用法

    Android中的Selector主要是用来改变ListView和Button控件的默认背景 其使用方法可以按一下步骤来设计 以在mylist view xml为例 1 创建mylist view xml文件 首先在res目录下新建draw
  • 栈与队列小总结

    思维导图 一 栈 栈 一种数据结构 具有后进先出的特点 有两种实现方式 第一种实现方式就是用数组结构来实现 第二种方式就是用链表的方式来实现 但是由于使用数组的方式来实现栈会更加的好 所以在这里我们用数组的方式来实现栈 栈的实现 1 栈的结
  • 红蓝对抗--蓝队

    2019年参加护网行动的时候 想着是信安专业 可以去赚点零花钱 蓝队的工作 后面总结了一下护网行动和蓝队的一些工作重心 刚刚换电脑的时候翻出来了这个文章 只是个人拙见 大佬勿喷 文章目录 一 团队组建 二 梳理资产 三 风险梳理 四 减少攻
  • 面试求职经历及遇到的部分问题

    转眼间已经工作一年多了 最近想换个工作环境 就选择了跳槽 跳槽对我们程序猿来说并没什么稀奇 但这是我第一次跳槽 也颇感激动 哈哈 总的来说 这次找工作还是相对去年来说比较容易的 毕竟已经工作一年了嘛 记得去年的时候投20份简历也不一定会有面
  • Lesson 7 Edge I

    一 图像分割与不连续 图像分割 segmentation 的目的是把图像中的像素分组 每组像素和图像中的物体强相关 图像分割需要确定图像中的不连续处 不连续处 discontinuity 包括孤立点 线段和边缘 edge 我们首先介绍edg
  • eclipse的new server里tomcat7.0根本选不上解决方法

    创建Tomcat v7 0 Server 不能进行下一步 解决方法 1 退出 eclipse 2 到 工程目录下 metadata plugins org eclipse core runtime 3 把org eclipse wst se
  • 查看函数和所在的行号

    查看Linux下 a库文件中文件 函数 变量等情况 2013 02 24 16 11 02 转载 在Linux 下经常需要链接一些 a的库文件 那怎么查看这些 a 中包 含哪些文件 函数 变量 1 查看文件 ar t a 2 查看函数 变量
  • 最全的Linux运维bash脚本常见用法总结

    删除重复的数组元素 创建临时关联数组 设置关联数组 值并发生重复赋值时 bash会覆盖该键 这 允许我们有效地删除数组重复 CAVEAT 需要bash4 示例功能 remove array dups Usage remove array d
  • 所有pyCharm2018或phpstorm2018版永久激活,亲测无问题

    注意 实际测试软件版本为phpstorm2018 2 3 破解补丁激活 到http idea lanyus com 这里下载补丁 下载 后并将 JetbrainsCrack release enc jar 放置到 D盘根目录 在 Pycha
  • [STM32F4]【把握住了】STM32F4驱动4路VL53L0测距你把握不住

    最近给朋友调试了STM32F407驱动VL53L0的激光测距 安装在机器人上的 遇到一些问题 这里发帖纪录一下 关于VL53L0的资料和代码在正点原子那里都有 但是正点原子只是驱动了一路VL53L0 很多问题都需要我们自己解决 一路的VL5
  • Pikachu靶场之XSS漏洞详解

    Pikachu靶场之XSS漏洞详解 前言 XSS漏洞简述 第1关 反射型xss get 第2关 反射性xss post 第3关 存储型xss 第4关 DOM型xss 第5关 DOM型xss x 第6关 xss盲打 第7关 xss之过滤 第8
  • ATM 网络安全:解决方案、技术和规格--网络大典

    比起 TCP IP 网络 异步传输模式 ATM 网络通常拥有较少的安全漏洞 因为它通常使用光纤作为媒介 并被当作骨干网络用于专用或半专用网络中 侵入 ATM 网络所需的投入是相当高的 然而在 ATM 网络中仍然存在着许多弱点 如信息嗅探 基
  • RTT-线程管理

    RTT 线程管理 官方API文档 https www rt thread org document api group thread html 概念 线程是竞争系统资源的最小运行单元 每个线程在自己的环境中运行 在任何时刻 只有一个线程得到
  • pip 安装 flask_sqlalchemy 报错

    报错一 Errno 13 Permission denied 报错二 ERROR After October 2020 you may experience errors when installing or updating packag
  • Mac电脑如何删除磁盘及双系统分区?

    对于一些新手来说 在使用Mac电脑时可能会选择对硬盘进行分区或者安装双系统 但是 如果后期不需要这些分区时 如何删除它们呢 首先在应用程序中找到实用工具并打开文件夹 然后选择磁盘工具打开 在左侧选中需要修改的磁盘 接着在右侧上方菜单中点击
  • 【当LINUX系统出现网络问题时该如何排查】

    当LINUX出现网络问题时该如何排查 具体问题具体分析 遵循相应的排查思路 一 网络不通时需要进行的处理 1 检测链路是否连通 2 网卡是否正常启用 3 检测路由与网关的配置 4 DNS工作状况 5 检测是否可以正常路由到远程主机 6 检查
  • selenium无登录状态爬取Boss直聘

    BOSS是我很早就实现数据爬取的网站 那会直接用request即可 最近再次尝试以前的代码发现 它做了一些反爬处理 当你直接访问例如https www zhipin com c101210100 b 西湖区 query 数据分析杭州这样的网
  • C++模板基础(五)

    函数模板 函数模板的 完全 特化 template lt gt void f int template lt gt void f int 并不引入新的 同名 名称 只是为某个模板针对特定模板实参提供优化算法 函数模板的特化本质上是实例化 有