C++模版SFIANE应用踩的一个小坑

一天一个C++大佬同事,突然截图过来一段代码:这写的啥呀,啰里吧嗦的,这个构造函数模板参数T1感觉是多余的呀

template<class T>
class TestClass
{
public:TestClass(){}//函数1template<class T1 = T, std::enable_if_t<std::is_same_v<int, T1>,bool> = true>TestClass(){//balabala}//函数2template<class T1 = T, std::enable_if_t<!std::is_same_v<int, T1>, bool> = true>TestClass(){//balabala}……
};int main() {TestClass<double> test;
} 

我说,这可能是那个不懂C++的人写出来的吧,看,写成下面的形式多简洁阿~

template<class T>
class TestClass
{
public:TestClass(){}//函数3template<std::enable_if_t<std::is_same_v<int, T>, bool> = true>TestClass(){}//函数4template<std::enable_if_t<!std::is_same_v<int, T>, bool> = true>TestClass(){}
};int main() {TestClass<double> test;
} 

于是就被打脸了,直接给我整出了一堆编译错误:

给我整一脸懵逼,上面函数1和2好好的,咋改成3和4就不行了呢? 看来,真的不能随便改别人代码。于是去网上查了查, 编译器错误 C2893 | Microsoft Learn

// C2893.cpp
//以下示例生成 C2893。
// compile with: /c /EHsc
#include<map>
using namespace std;
class MyClass {};template<class T>
inline typename T::data_type
// try the following line instead
// inline typename  T::mapped_type
f(T const& p1, MyClass const& p2);template<class T>
void bar(T const& p1) {MyClass r;f(p1,r);   // C2893
}int main() {map<int,int> m;bar(m);
}

发生 C2893 的原因是,f 的模板参数 T 被推断为 std::map<int,int>,但 std::map<int,int> 没有成员 data_type(无法使用 T = std::map<int,int> 实例化 T::data_type)。

看来编译错误产生的原因是 std::enable_if_t<std::is_same_v<int, double>, bool>即 std::enable_if_t<false, bool>是未定义类型导致的。可是函数1和函数3到底有什么区别呢? 绞尽脑汁,百思不得其解,最痛通过找不同的方式,终于悟了:这两个唯一的差别就是,T是类模板参数,T1是类构造函数模板参数。后面回顾了一下Sfiane相关的知识,终于找到问题的根本原因:

SFINAE 原理

SFINAE(Substitution Failure Is Not An Error)是 C++ 模板机制的一部分,当模板参数替换导致的模板不合法时,模板不会引发编译错误,而是会被编译器静默排除。然而,SFINAE 只适用于函数模板参数替换阶段,而不适用于非模板参数替换阶段的错误。

我们先来看一下函数3

template<std::enable_if_t<std::is_same_v<int, T>, bool> = true>
TestClass()
{
}

在这个函数模板中:

std::enable_if_t<std::is_same_v<int, T>, bool> = true 是模板参数的默认参数。编译器会在函数模板实例化时尝试解析这部分默认参数。

  • std::enable_if_t<std::is_same_v<int, T>, bool> 依赖于 T,它是类模板 TestClass<T> 的参数。在 类模板实例化时,编译器已经需要评估这个表达式来确定默认值是否有效。
  • 如果 T 不等于 int(例如 TestClass<double>),std::is_same_v<int, T> 变成 false,这时 std::enable_if_t<false, bool> 试图生成一个无效类型,这会导致编译错误,而不是被 SFINAE 排除。

SFINAE 只作用于模板参数替换期间产生的错误,而这个默认参数的实例化所依赖的类型T属于类模板参数,不属于该函数模板参数替换阶段。这意味着:

  • 编译器在遇到默认参数时需要立即评估它,而不是等到参数替换期间再进行评估。
  • 因此,如果默认参数表达式在定义时无效(比如 std::enable_if_t<false, bool>),编译器会报错,而不是通过 SFINAE 排除它。

我们再来看一下函数1

template<class T1 = T, std::enable_if_t<std::is_same_v<int, T1>, bool> = true>
TestClass(int i)
{
}

在函数1中,T1 是一个新的模板参数,并且默认值为 T。因此,SFINAE 是在模板参数 T1 替换阶段应用的:

  • 如果 T1 不满足 std::is_same_v<int, T1>,则该模板的实例化会失败,SFINAE 会将此构造函数排除在重载集合之外。

这里的关键在于:

  • T1 是函数模板的一个参数,所以 std::enable_if_t 检查是在模板参数替换阶段发生的。
  • 如果替换导致无效,则会被 SFINAE 静默排除,不会报编译错误。

这个例子中通过引入额外的模板参数(如 T1),你可以推迟 enable_if 的检查,使其在模板参数替换阶段才进行,从而避免编译错误。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

vSAN05:vSAN延伸集群简介与创建、资源要求与计算、高级功能配置、维护、故障处理

目录 vSAN延伸集群延伸集群创建延伸集群的建议网络配置vSAN延伸集群的端口见证主机的资源要求vSAN延伸集群中见证节点带宽占用vSAN延伸集群的允许故障数vSAN延伸集群不同配置下的空间占用 vSAN延伸集群的HA配置vSAN延伸集群的DRS配置vSAN存储策略以及虚拟机/主机策略的互操作vS…

十四、深入理解Mysql索引底层数据结构与算法

文章目录 一、索引的本质1、索引是帮助MySQL高效获取数据的排好序的数据结构2、索引的数据结构3、数据结构可视化网站 二、常见数据结构介绍1、B-Tree2、BTree&#xff08;B-Tree变种&#xff09;3、Hash结构 三、存储引擎的索引实现1、MyISAM存储引擎索引实现MyISAM索引文件和…

AI配音(声音克隆)

Fish Audio: Free Generative AI Text To Speech & Voice Cloning 【【AI配音】终于找到免费 & 小白友好的声音克隆软件了&#xff01;真人相似度98%!】https://www.bilibili.com/video/BV1MwbFeCE2X?vd_source3cc3c07b09206097d0d8b0aefdf07958 我终于找到总这3款免…

新机配置Win11

Win11跳联网 在连接网络的界面输入ShiftF10打开命令行&#xff0c;然后输入oobe\bypassnro然后会重启&#xff0c;在联网的界面就可以进行跳过了。 编码 在中国大陆Windows使用的编码是GBK编码 查看电脑系统版本 WinR输入winver即可 桌面图标 设置->个性化->主题…

【机器学习】深度学习、强化学习和深度强化学习?

深度学习、强化学习和深度强化学习是机器学习的三个重要子领域。它们有着各自独特的应用场景和研究目标&#xff0c;虽然都属于机器学习的范畴&#xff0c;但各自的实现方式和侧重点有所不同。 1. 深度学习&#xff08;Deep Learning&#xff09; 深度学习是一种基于神经网络的…

Vite多环境配置与打包:

环境变量必须以VITE开头 1.VITE_BASE_API&#xff1a; 在开发环境中设置为 /dev-api&#xff0c;这是一个本地 mock 地址&#xff0c;通常用于模拟后端接口。 2.VITE_ENABLE_ERUDA&#xff1a; 设置为 "true"&#xff0c;表示启用调试工具&#xff0c;通常是为了…

【MySQL】-- 库的操作

文章目录 1. 查看数据库1.1 语法 2. 创建数据库2.1 语法2.2 示例2.2.1 创建一个名为java114的数据库2.2.2 创建数据库java114&#xff0c;如果数据库不存在则创建2.2.3 查看警告信息 3. 字符集编码和校验&#xff08;排序&#xff09;规则3.1 查看数据库支持的字符集编码3.2 查…

动态SLAM总结二

文章目录 Mapping the Static Parts of Dynamic Scenes from 3D LiDAR Point Clouds Exploiting Ground Segmentation&#xff1a;&#xff08;2021&#xff09;RF-LIO&#xff1a;&#xff08;2022&#xff09;RH-Map&#xff1a;&#xff08;2023&#xff09;Mapless Online …

子比主题美化 – 添加天气教程

前言 经常看到很多的网站顶部或者侧边有显示天气状态的小条幅&#xff0c;看着也美观&#xff0c;寻思着也在自己的小站上显示天气。大体的思路是能识别用的ip地址来确认位置然后以代码形式在前台显示出。 经过在百度上搜索一番&#xff0c;发现一个很不错的天气api&#xff…

万界星空科技MES数据集成平台

制造执行系统MES作为连接企业上层ERP系统和现场控制系统的桥梁&#xff0c;承担了实时数据采集、处理、分析和传递的重要任务。MES数据集成平台是一个集成各类数据源&#xff0c;将数据进行整合和统一管理的系统&#xff0c;通过提供标准化接口和协议&#xff0c;实现数据的无缝…

GOME数据IDL处理

GOME数据后缀为xdr 数据url&#xff1a;https://lweb.cfa.harvard.edu/~xliu/GMLV3/ 官方文档给出的读取方式为IDL&#xff08;restore方式&#xff09;&#xff1a; 以下是包含的数据字段&#xff1a; ;print,LONS ;print,ALB ;print,NLON ;print,NLAT ;print,LATS ; AVGK…

基于ssm 框架的java 开发语言的 在线教育学习平台系统设计与实现 源码 论文

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm springcloud等开发框架&#xff09; vue .net php phython node.js uniapp小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆…

Kotlin真·全平台——Kotlin Compose Multiplatform Mobile(kotlin跨平台方案、KMP、KMM)

前言 随着kotlin代码跨平台方案的推出&#xff0c;kotlin跨平台一度引起不少波澜。但波澜终归没有掀起太大的风浪&#xff0c;作为一个敏捷型开发的公司&#xff0c;依然少不了Android和iOS的同步开发&#xff0c;实际成本和效益并没有太多变化。所以对于大多数公司来说依然风平…

系统设计,如何设计一个秒杀功能

需要解决的问题 瞬时流量的承接防止超卖预防黑产避免对正常服务的影响兜底方法 前端设计 利用 CDN 缓存静态资源&#xff0c;减轻服务器的压力在前端随机限流按钮防抖&#xff0c;防止用户重复点击 后端设计 Nginx 做统一接入&#xff0c;进行负载均衡与限流用 sentinel 等…

工具 | 红队大佬亲测5款推荐的Burpsuite插件

*免责声明&#xff1a;* *本文章仅用于信息安全技术分享&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作…

【LeetCode-热题100-128题】官方题解好像有误

最长连续序列 题目链接&#xff1a;https://leetcode.cn/problems/longest-consecutive-sequence/?envTypestudy-plan-v2&envIdtop-100-liked 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的…

LLM大模型学习精要系列(一):掌握基础,开启大模型之旅

1.前言 1.1 基础模型研究 2023 年&#xff0c;随着 LLM 技术的发展&#xff0c;中国模型研究机构的开源模型迎来了爆发式的增长&#xff1a; 2023 年 3 月&#xff0c;智谱 AI 首先在魔搭社区发布了 ChatGLM-6B 系列&#xff0c;ChatGLM-6B 是一个开源的、支持中英双语问答的…

如何只修改obsidian图片链接为markdown

如何只修改obsidian图片链接为markdown 前言插件配置 使用注意 前言 适合有一定了解obsidian用法和插件市场&#xff0c;还有相对路径的人 插件 在obsidian插件市场搜索—开梯子 配置 首先使用ctrlp打开命令面板&#xff0c;也可以在左侧通过图标打开命令面板&#xff0c…

车载电子电气架构--- 车载诊断DTC全覆盖分类

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…