SFINAE

说说SFINAE SFINAE的介绍,例子及讲解。 阅读详情

SFINAE 是 C++ 模板编程中的一个非常重要的技术概念,英文全称是 Substitution Failure Is Not An Error,中文通常翻译为 替换失败不是错误。

首先看一个概念

1、函数模板

函数的传参类型

写法 含义 是否类型检查 是否数量固定
void func(int a) 只能接受一个 int 参数 ✅ 是 ✅ 是
template void func(T a) 接受任意类型的一个参数 ✅ 是 ✅ 是
void func(…) 接受任意数量和类型的参数(无类型检查)

void func(…);
是一个 接受任意参数、任意数量 的函数,是模板匹配失败后的终极兜底方案,常用于配合 SFINAE 做默认实现。void func(…) 这种写法叫做 C风格的可变参数函数(variadic function)

这个 func(...) 是一个 万能匹配兜底版本:
因为 ... 什么都能接
所以不管什么类型、多少参数,都能进
它就成了 如果上面模板失败了,就自动调用这个的“兜底方案”

2、decltype

decltype 用来获取表达式的类型,它会告诉编译器“这个表达式的类型到底是什么”。
简单来说,decltype(expr) 就是返回 expr 的静态类型(编译时确定的类型),可以用来定义变量类型或模板返回类型等。

int x = 10;
decltype(x) y = 20;  // y 的类型是 int,跟 x 一样

int& ref = x;
decltype(ref) ref2 = x;  // ref2 是 int&,引用类型

auto z = x + 1;   // auto推断类型
decltype(x + 1) w;  // decltype 也能推断,w 的类型是 int

应用在函数模板上

template<typename T>
auto func(T t) -> decltype(t.foo()) {
    return t.foo();
}

这行代码的意思是:
函数 func 返回类型是 t.foo() 这个表达式的类型
编译器会根据 t.foo() 的返回类型自动推断 func 的返回类型

编译期确定返回类型
decltype(expr) 在编译阶段就确定 expr 的类型。
它不会在程序运行时去判断。

3、SFINAE

它是一种模板实例化时的编译器机制/规则。而非关键字

SFINAE 就像编译器给模板实例化过程加了一个“容错开关”:
如果替换时成功 → 这个模板有效
替换失败 → 这个模板被跳过,继续找其他模板
全失败 → 报错

如果模板发现这个模板能用,就使用这个模板,如果模板不能用,再找下一个模板,直到找到为止,如果都不能用,最后还有默认模板(不论什么参数,几个参数)都能用

#include <iostream>

// 只有有foo成员函数的类型可以调用这个版本
template<typename T>
auto func(T t) -> decltype(t.foo()) {
    std::cout << "调用了有foo成员函数的版本\n";
}

// 默认模板
template<typename T>
void func(...) {
    std::cout << "调用了默认版本\n";
}

struct A {
    void foo() {}
};

struct B {};

int main() {
    A a;
    B b;

    func(a);  // 输出: 调用了有foo成员函数的版本
    func(b);  // 输出: 调用了默认版本
}

func(a):a 有 foo(),第二个模板实例化成功,调用它
func(b):b 没有 foo(),第二个模板实例化失败,编译器自动忽略,调用默认版本

总结
SFINAE 是模板参数替换失败时不报错,而是忽略该模板的一种规则
让我们可以写出“如果满足条件就启用这个模板,否则忽略它”的代码
主要用在复杂的模板重载和类型特征检测中

为什么要用SFINAE?

1、实现模板的条件选择(模板重载决策)
通过SFINAE可以根据模板参数的性质,选择不同的模板实现。例如,可以实现某个函数模板只在传入类型满足某种条件时才启用,而不满足时就忽略这个模板,从而达到重载的效果。

2、编写更灵活、泛化的代码
SFINAE允许模板编程者在编译期对类型做检测(比如某个类型是否有某个成员函数、是否满足某个接口等),根据检测结果来做不同的代码路径选择。

3、避免编译时错误,提高代码健壮性
传统写法如果类型不匹配,编译直接报错。SFINAE让编译器能够尝试多个模板版本,只启用可行的那个,避免无效模板导致编译失败。
C++ SFINAE 机制详解 C++ SFINAE 阅读详情

相关推荐

S7-200 SMART Modbus RTU从站配置与调试实战指南

本文提供了一份详细的S7-200 SMART PLC配置为Modbus RTU从站的实战指南。内容涵盖从硬件基础、软件准备、指令库调用、核心编程到地址映射与调试排错的完整流程。重点解析了MBUS_INIT与MBUS_SLAVE指令的关键参数配置,并深入探讨了Modbus地址与PLC内部V存储区的对应关系,帮助工程师快速打通通讯链路,实现与上位机、触摸屏等主站设备的稳定数据交互。

potato的博客 751

现代C++之SFINAE

介绍c++的SFINAE概念:类成员的编译时内省0.导语1.C++自省?2.老式的C++98方式2.1重载决议2.2 SFINAE2.3 sizeof运算符2.4 结合一切2.5 实现我...

Francis的博客 5696

liquibase扩展支持达梦数据库

近期项目中需要支持国产数据库,需要liquibase底层支持达梦数据库,记录下操作的详细步骤以便分享。 1.liquibase支持的数据库很多如MySQL, PostgreSQL, Oracle, Sql Server, DB2。但是达梦数据库并不支持,所以需要新建DMDatabase类来适配达梦数据库。达梦语法和Oracle很像所以只需要复制liquibase-core下的Oracle Database做些修改就可了。以下为需要修改的地方 public class DMDatabase extends A

qq_43677719的博客 5472

C++之SFINAE

SFINAE

leapmotion的博客 1298

基于大模型的重度膝关节骨关节炎全流程预测与治疗方案研究

本研究基于大模型构建了重度膝关节骨关节炎(KOA)预测体系,涵盖术前风险预测、手术方案优化、术中监测和术后康复指导全流程。通过分析临床和影像数据,模型在手术风险预测准确率(85%)、并发症预警(血栓预测准确率88%)等方面显著优于传统方法。研究实现了临床数据与AI技术的深度融合,术前预测指导麻醉选择(如高危患者推荐椎管内麻醉),术中实时监测生命体征,术后个性化康复方案使患者HSS评分平均提升45分。

嵌入式毕设/课设资料清单(速查手册·文档模板·题库,持续更新)→ 见最新文章 1389

微信支付开发之平台给用户转账到零钱的功能

请求消息中应包含商家批次单号、转账名称、appid、转账总金额、转账总笔数、转账openid、收款用户姓名等信息。批次已受理成功,若发起批量转账的30分钟后,转账批次单仍处于该状态,可能原因是商户账户余额不足等。【转账场景ID】 该批次转账使用的转账场景,如不填写则使用商家的默认场景,如无默认场景可为空,可前往“商家转账到零钱-前往功能”中申请。【转账总笔数】 一个转账批次单最多发起一千笔转账。【商家批次单号】 商户系统内部的商家批次单号,要求此参数只能由数字、大小写字母组成,在商户系统内部唯一。

程序员weixin_sodomany的博客 3449

C++20 概念与约束(1)—— SFINAE

众所周知,C++在使用模板时,如果有多个模板匹配,则编译器会选择最匹配的一个模板进行实例化,这也正是模板特化和偏特化的依据。根据上面这张图中的现象,列举下面几个示例:1、不存在模板的情况下, foo(1.0) 中的 1.0 将进行隐式转换。2、若存在模板,模板匹配的优先级高于隐式转换。3、若不存在实例, 编译器将用最合适的模板(图中的特化版本)进行实例化。4、当然,在不存在实例也不存在匹配模板的情况下,编译器才会报错。从上述现象可知,优先级中,模板实例化 > 隐式类型转换 > 报错。

Peeepi的博客 2162

手把手教你用STM32F103C8T6驱动HUB75 LED点阵屏(附74HC595级联代码)

本文详细介绍了如何使用STM32F103C8T6开发板驱动HUB75接口的LED点阵屏,包括硬件连接、74HC595级联代码、时序控制及灰度显示实现。通过实战案例展示动态文字显示和性能优化技巧,帮助开发者快速掌握LED点阵屏驱动技术。

weixin_42623010的博客 341

《C++那些事》之SFINAE

介绍c++的SFINAE概念:类成员的编译时内省0.导语1.C++自省?2.老式的C++98方式2.1重载决议2.2 SFINAE2.3 sizeof运算符2.4 结合一切2.5 实现我们的想法2.6 小结3.C++11方式3.1 decltype, declval, auto & co4.融合时间4.1 第一种解决方案4.2 第二种解决方案5.C++14的优势5.2 auto与lambd...

Francis的博客 875

量产导入 | 产品可靠性测试标准完整大集合(JEDEC/IEC/SAE…)

产品可靠性测试是产品质量保证中的重要一环, 包含有Pre-con, aging(寿命)和ESD(静电)等, 下面就收集了权威标准JEDEC全系列, 请参照如下 同时也附上其它的可靠性标准供大家参考及交叉理解, 可能侧重点不同, 大家可以参考下。

叫好与叫座虽然不是对立面,但想在同一个作品中达到双重效果很难。 1660

绿盾用户使用看图软件每次都需要把图片解密之后才能打开查看,怎么才能不用这么麻烦打开就能看

Win10专业版绿盾控制台7.0看图软件FastStone Image Viewer。

本博客,博文仅代表个人操作经验,不能完全解决你的问题,仅供参考,佛系回复。 1201

利用SFINAE检测成员函数

本文介绍了一种利用SFINAE技术检测类成员函数存在性的C++实现方案。通过定义access辅助类进行成员函数调用测试,结合decltype和std::declval在编译期检测函数可调用性。核心是使用宏CEREAL_MAKE_HAS_MEMBER_FUNC封装检测逻辑,生成has_member_xxx类型特征。最后通过PROCESS_IF和PROCESS_IF_NOT宏配合模板函数重载,实现根据成员函数存在性选择不同处理路径。该方案可用于反射、序列化等需要编译期类型检查的场景

qq_47355554的博客 928

13、基因相似性度量的相关性及特征选择研究

本文研究了基因相似性度量和特征选择在生物学中的应用,详细介绍了GO术语相似性度量的多种方法,包括语义度量和路径长度度量,并分析了不同方法在酵母和人类数据集上的表现。研究发现,Avg-sum方法和基于路径长度的度量在多数情况下效果较好。此外,通过晚期辐射毒性预测的案例研究,探讨了特征选择的重要性及可能面临的过拟合和噪声干扰问题,并提出了相应的解决策略。

js777的博客 127

C++学习:六个月从基础到就业——模板编程:SFINAE原则

SFINAE是"Substitution Failure Is Not An Error"(替换失败不是错误)的缩写,它是C++模板实例化过程中的一个基本原则。简单来说,当编译器尝试用具体类型替换模板参数时,如果替换导致了无效的代码(例如,使用了不存在的类型成员或无效的运算),编译器不会立即报错,而是简单地将该模板从重载解析的候选集中移除。这一原则允许我们编写基于类型特性的条件模板代码。例如,我们可以为具有特定成员函数的类型提供一个版本的函数,为其他类型提供另一个版本。// 这个版本只对整数类型有效。

qq_53773901的博客 1875

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C++ 萃取技术——使用SFINAE特性的信息萃取

SFINAE(Substitution Failure Is Not An Error,替换失败并不是一个错误)是实现类型萃取中一个重要的技巧,它允许编译器在模板实例化过程中忽略那些会导致错误的替换,而不是产生编译错误。

慢慢记录,慢慢更新。 1468

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

C++ SFINAE

SFINAE是C++模板编程中的一个重要概念,全称是"Substitution Failure Is Not An Error"(替换失败不是错误)。它允许我们在编译期间基于类型特性选择正确的函数重载或模板特化。

琅嬛福地 743

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

C++那些事之SFINAE

介绍c++的SFINAE概念:类成员的编译时内省0.导语1.C++自省?2.老式的C++98方式2.1重载决议2.2 SFINAE2.3 sizeof运算符2.4 结合一切2.5 实现我们的想法2.6 小结3.C++11方式3.1 decltype, declval, auto & co4.融合时间4.1 第一种解决方案4.2 第二种解决方案5.C++14的优势5...

Francis的博客 546

C++惯用法之SFINAE

SFINAE惯用法是什么?在谈SFINAE之前我们先来看一段代码,一切从这段代码开始。template <typename T> void show(typename T::iterator x, typename T::iterator y) { for (; x != y; ++x) cout << *x << endl; }int main() { show<int>(16,

zyfforlinux 3164

跟我学c++高级篇——模板元编程之六SFINAE

SFINAE,对于想在模板编程中有更深的想法时,建议还是要认真学习。其实SFINAE更像是模板编程中更进阶的一种用法,虽然它可能在复杂的应用情况有些晦涩难懂,但既然决定想搞c++的模板编程,一些精深的东西还是需要去学习的。特别之于模板的元编程,更是如此。虽然有了concepts,但看以前的代码还是需要懂得这个技术的。

fpcc的专栏 4768

SFINAE 极简介绍

首先推荐讲SFINAE我认为最好的两个资料,一个是cppreferenceSFINAE,一个是channel9上Stephan T Lavavej讲的三个series:Core CPP,STL, Advacned STL其中的某一集。。。的确忘了是哪集了。这两个资料有深入有浅出,最重要的是讲明白了SFINAE的本质,而不是上来就一段代码告诉你这个就是SFINAE,看完了就看完了而已,完全和其他知识

rreference 1436

C++惯用法: 通过std::decltype来SFINAE掉表达式

SFINAE 技术,即匹配失败不是错误,英文Substitution Failure Is Not An Error,其作用是当我们在进行模板特化的时候,会去选择那个正确的模板,避免失败。 SFINAE一般用于函数重载和编译期间类型检查,标准库中很多type traits模板就是通SFINAE来实现的。 看个具体的例子: 核心的代码是在实例化check_has_member_id对象的时候,通过模板参数T的类型,决定了结构体中对象value的值。而value的

红军不怕远征难,万水千山只等闲 1821

C++ 模板简介(一)—— SFINAE

SFINAE, 类型检查, Concepts ​ SFINAE 机制是组成 C++ 模板机制及类型安全的相当重要的基础。全称是 Substitution failure is not an error。大概的意思就是只要找到了可用的原型(比如函数模板、类模板等)就不会编译错误。SFINAE 可以被用来进行模式匹配。在尝试本篇代码时请打开 C++17。 https://en.cppreference...

とある黄鱼のOIブログ 1700

一文速通C++ SFINAE

带你一文速通SFINAE。前文我们介绍了全特化、偏特化、泛化(重载决议),以及类型萃取。我们可不可以更进一步的,在编译期对类型进行更多的“要求”?答案是肯定的,C++20中已经提供了concept,但有时候我们不得不在C++17及之前的环境中进行开发,这时就需要使用SFINAE啦。

weixin_41733034的博客 911

C++ 中 SFINAE 详解:模板编译期的“替换失败不是错误”

基本原则:模板参数替换过程中,如果产生了无效的代码(在函数签名中),编译器不报错,而是将该候选模板从重载集合中移除,继续尝试其他模板。只有所有候选都失败时才报错。适用范围:SFINAE 主要作用于函数签名(返回类型、参数类型、模板参数声明),对于函数体内部的错误或类模板定义中的错误,SFINAE 不适用。关键应用:条件性地启用或禁用模板void_t技巧:检测成员函数和成员类型的存在性类型萃取与标签分发:根据类型特性在编译期选择不同实现定制等标准萃取现代替代方案C++17。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 1221

深入浅出SFINAE

An introduction to C++'s SFINAE concept: compile-time introspection of a class member Posted on Sat 31 October 2015 inC++ 原文链接:http://jguegant.github.io/blogs/tech/sfinae-introduction.html ...

b1206的博客 582
上一篇: operator关键字
下一篇: new和mallo的区别
C++_girl
博客等级 码龄7年 32粉丝 60原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值