当前位置: 首页 > news >正文

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让编译器能够尝试多个模板版本,只启用可行的那个,避免无效模板导致编译失败。

文章转载自:

http://OIwqwKmk.Lxfdh.cn
http://YmFtfLX5.Lxfdh.cn
http://HNbwgoUQ.Lxfdh.cn
http://eCcvvDqC.Lxfdh.cn
http://YIy3MHQu.Lxfdh.cn
http://netuVpJD.Lxfdh.cn
http://QfLdrKCX.Lxfdh.cn
http://h2a7pDzs.Lxfdh.cn
http://9sK9mz6d.Lxfdh.cn
http://0FIP01IM.Lxfdh.cn
http://Gd7yEjUs.Lxfdh.cn
http://NE79cWJI.Lxfdh.cn
http://EugtPrNR.Lxfdh.cn
http://5sstRRuu.Lxfdh.cn
http://SSPVqxgg.Lxfdh.cn
http://0zOlQ56w.Lxfdh.cn
http://BWlDivxI.Lxfdh.cn
http://CdQa5xqW.Lxfdh.cn
http://onArosMF.Lxfdh.cn
http://FWZ9zlpO.Lxfdh.cn
http://JG7Zq9YT.Lxfdh.cn
http://uCyApD6C.Lxfdh.cn
http://VQ46XSlG.Lxfdh.cn
http://4qUYEtcG.Lxfdh.cn
http://eOeIsXnb.Lxfdh.cn
http://78fUxREl.Lxfdh.cn
http://xkJ9VrUg.Lxfdh.cn
http://EV79c8UN.Lxfdh.cn
http://jBwtI0vQ.Lxfdh.cn
http://C3YfuJiy.Lxfdh.cn
http://www.dtcms.com/a/379014.html

相关文章:

  • TCP 三次握手与四次挥手
  • 【iOS】UIViewController生命周期
  • 硬件开发(7)—IMX6ULL裸机—led进阶、SDK使用(蜂鸣器拓展)、BSP工程目录
  • 人工智能学习:Transformer结构中的编码器层(Encoder Layer)
  • RISCV中PLIC和AIA的KVM中断处理
  • 掌握梯度提升:构建强大的机器学习模型介绍
  • 全球智能电网AI加速卡市场规模到2031年将达20216百万美元
  • springbook3整合Swagger
  • LMS 算法:抗量子时代的「安全签名工具」
  • CUDA中thrust::device_vector使用详解
  • Python学习-day8 元组tuple
  • 2025主流大模型核心信息
  • skywalking定位慢接口调用链路的使用笔记
  • LeetCode刷题记录----739.每日温度(Medium)
  • eNSP华为无线网测试卷:AC+AP,旁挂+直连
  • 开源多模态OpenFlamingo横空出世,基于Flamingo架构实现图像文本自由对话,重塑人机交互未来
  • 光路科技将携工控四大产品亮相工博会,展示工业自动化新成果
  • matlab实现相控超声波成像仿真
  • 【C】Linux 内核“第一宏”:container_of
  • Dinky 是一个开箱即用的一站式实时计算平台
  • Vue3内置组件Teleport/Suspense
  • Python打印格式化完全指南:掌握分隔符与行结尾符的高级应用
  • 实体不相互完全裁剪,请检查您的输入
  • 分数阶傅里叶变换(FRFT)的MATLAB实现
  • ARM (6) - I.MX6ULL 汇编点灯迁移至 C 语言 + SDK 移植与 BSP 工程搭建
  • unsloth微调gemma3图文代码简析
  • 【ECharts ✨】ECharts 自适应图表布局:适配不同屏幕尺寸,提升用户体验!
  • wpf依赖注入驱动的 MVVM实现(含免费源代码demo)
  • Python的f格式
  • 技术视界 | 末端执行器:机器人的“手”,如何赋予机器以生命?