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

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

template<class T>
class TestClass
{
public:
    TestClass(){}

    //函数1
    template<class T1 = T, std::enable_if_t<std::is_same_v<int, T1>,bool> = true>
    TestClass()
    {
         //balabala
    }

    //函数2
    template<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(){}

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

    //函数4
    template<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.mfbz.cn/a/887616.html

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

相关文章

VTC视频时序控制器,TPG图像测试数据发生器,LCD驱动——FPGA学习笔记19

详情可以见LCD篇 LCD彩条显示——FPGA学习笔记10_依次显示红绿蓝三个通道-CSDN博客 一、VTC简介 Video Timing Controller 缩写 VTC 是我们在所有涉及 FPGA 图像、 FPGA 视频类方案中经常用到的一种用于产生视频时序的控制器。 本课以 VGA 为切入点&#xff0c; 学习视频传输…

Java IO流全面教程

此笔记来自于B站黑马程序员 File 创建对象 public class FileTest1 {public static void main(String[] args) {// 1.创建一个 File 对象&#xff0c;指代某个具体的文件// 路径分隔符// File f1 new File("D:/resource/ab.txt");// File f1 new FIle("D:\\…

【Golang】Go语言中时间time相关处理方法

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

将列表中的各字符串sn连接成为一个字符串s使用;将各sn间隔开os.pathsep.join()

【小白从小学Python、C、Java】 【考研初试复试毕业设计】 【Python基础AI数据分析】 将列表中的各字符串sn 连接成为一个字符串s 使用;将各sn间隔开 os.pathsep.join() [太阳]选择题 下列说法中正确的是? import os paths ["/a", "/b/c", "/d&q…

Linux 系统五种帮助命令的使用

Linux 系统五种帮助命令的使用 本文将介绍 Linux 系统中常用的帮助命令&#xff0c;包括 man、–help、whatis、apropos 和 info 命令。这些命令对于新手和有经验的用户来说&#xff0c;都是查找命令信息、理解命令功能的有力工具。 文章目录 Linux 系统五种帮助命令的使用一…

2024年计算机视觉与艺术研讨会(CVA 2024)

目录 基本信息 大会简介 征稿主题 会议议程 参会方式 基本信息 大会官网&#xff1a;www.icadi.net&#xff08;点击了解参会投稿等信息&#xff09; 大会时间&#xff1a;2024年11月29-12月1日 大会地点&#xff1a;中国-天津 大会简介 2024年计算机视觉与艺术国际学术…

初阶C语言-指针

1.指针是什么&#xff1f; 理解指针的两个要点&#xff1a; 1.指针是内存中一个最小单元的编号&#xff0c;也就是地址 2.口头语中说的指针&#xff0c;通常是指指针变量&#xff0c;是用来存放内存地址的变量 总结&#xff1a;指针就是地址&#xff0c;口语中说的指针通常是指…

【Spring】“请求“ 之传递 JSON 数据

文章目录 JSON 概念JSON 语法JSON 的语法JSON 的两种结构 JSON 字符串和 Java 对象互转JSON 优点传递 JSON 对象 JSON 概念 JSON&#xff1a;JavaScript Object Notation【JavaScript 对象表示法】 JSON 就是一种数据格式&#xff0c;有自己的格式和语法&#xff0c;使用文本…

Vue组件库Element-ui

Vue组件库Element-ui Element是一套为开发者、设计师和产品经理准备的基于Vue2.0的桌面端组件库。Element - 网站快速成型工具 安装element-ui npm install element-ui # element-ui版本&#xff08;可以指定版本号引入ElementUI组件库&#xff0c;在main.js中添加内容得到&…

IDEA的lombok插件不生效了?!!

记录一下&#xff0c;防止找不到解决方案&#xff0c;已经遇到好几次了 前面啰嗦的多&#xff0c;可以直接跳到末尾的解决方法&#xff0c;点击一下 问题现场情况 排查过程 确认引入的依赖正常 —》&#x1f197; idea 是否安装了lombok插件 --》&#x1f197; 貌似没有问题…

保姆级手把手使用YOLOv11训练自己数据集(含源代码、网络结构、模型检测和转换 、数据集查找、模型训练)

文章目录 前言项目地址项目内容&#xff1a;网络模型结构性能测试任务描述任务内容 项目运行模型训练 前言 本教程内含YOLOv11网络结构图训练教程推理教程数据集获取等有关的内容~ 项目地址 YOLO11是Ultralytics YOLO系列实时目标检测器的最新迭代版本&#xff0c;它以尖端的…

北交大研究突破:塑料光纤赋能低成本无摄像头AR/VR眼动追踪技术

北交大研究&#xff1a;探索无摄像头低成本AR/VR眼动追踪新路径 在AR/VR技术领域&#xff0c;眼动追踪作为一项关键技术&#xff0c;对于提升用户体验、优化渲染效率具有重要意义。然而&#xff0c;传统的眼动追踪方案多依赖于高成本的摄像头&#xff0c;这不仅增加了设备的制造…

Python 工具库每日推荐 【Pandas】

文章目录 引言Python数据处理库的重要性今日推荐:Pandas工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:销售数据分析案例分析高级特性数据合并和连接时间序列处理数据透视表扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 TypeScrip…

市面上8款AI论文大纲一键生成文献的软件推荐

在当前的学术研究和写作领域&#xff0c;AI论文大纲自动生成软件已经成为提高写作效率和质量的重要工具。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。本文将分享市面上8款AI论文大纲一键生成文献的软件&#xff0c;并特别推…

一文了解构建工具——Maven与Gradle的区别

目录 一、Maven和Gradle是什么&#xff1f; 构建工具介绍 Maven介绍 Gradle介绍 二、使用时的区别&#xff1a; 1、新建项目 Maven&#xff1a; Gradle&#xff1a; 2、配置项目 Maven&#xff1a; Gradle&#xff1a; 3、构建项目——生成项目的jar包 Gradle&…

用小学生可以理解的语言讲一下什么是大模型

好的&#xff0c;用小学生的语言来说&#xff0c;大模型就像是一个超级聪明的机器人老师&#xff0c;它懂得很多东西&#xff0c;可以帮助我们做很多事情。 1. **懂得很多**&#xff1a;大模型知道很多知识&#xff0c;就像一个巨大的图书馆&#xff0c;里面有很多书&#xff0…

IDEA 2024.3 预览:把开发者感动到哭了

幸运的人&#xff0c; 一生都被童年治愈&#xff1b; 不幸的人&#xff0c; 一生都在治愈童年 只有勇敢的人 和有钱的人才能先享受世界 缘分就是我还不知道 会见到你就误打误撞般 遇见了你 最近 IDEA 又发布了最新的 2024.3 的预览版本 EAP&#xff0c;把开发者的心激动的…

今日指数-day08实战完整代码

今日指数-day08 1. 个股最新分时行情数据 1.1 个股最新分时行情功能说明 1&#xff09;个股最新分时行情功能原型 2&#xff09;个股最新分时行情数据接口分析 功能描述&#xff1a;获取个股最新分时行情数据&#xff0c;主要包含&#xff1a;开盘价、前收盘价、最新价、最…

AI周报(9.29-10.5)

AI应用-Elayne公司临终规划和自动化遗产结算 创业公司Elayne成立于2023年&#xff0c;由Adria Ferrier和Jake Grafenstein共同创立&#xff0c;Adria Ferrier担任CEO&#xff0c;总部位于科罗拉多州丹佛市。 Elayne公司专注于遗产规划和结算领域&#xff0c;通过人工智能技术…

【Diffusion分割】CTS:基于一致性的医学图像分割模型

CTS: A Consistency-Based Medical Image Segmentation Model 摘要&#xff1a; 在医学图像分割任务中&#xff0c;扩散模型已显示出巨大的潜力。然而&#xff0c;主流的扩散模型存在采样次数多、预测结果慢等缺点。最近&#xff0c;作为独立生成网络的一致性模型解决了这一问…