0

0

c++中的概念(Concepts)和SFINAE有什么关系_c++模板约束的演进【C++20】

冰火之心

冰火之心

发布时间:2025-12-22 11:35:10

|

961人浏览过

|

来源于php中文网

原创

Concepts 是 C++20 对 SFINAE 的演进而非替代,通过显式命名、清晰错误信息、声明处约束检查和语法封装,解决了 SFINAE 写法绕、读晦涩、错难懂、不可复用等痛点,但底层仍依赖 SFINAE。

c++中的概念(concepts)和sfinae有什么关系_c++模板约束的演进【c++20】

Concepts 是 C++20 引入的正式语法机制,用来直接表达模板参数的约束条件;而 SFINAE(Substitution Failure Is Not An Error)是 C++11/14 时期“曲线救国”式实现模板约束的技术手段——Concepts 本质上是对 SFINAE 约束逻辑的语法封装与语义升华,不是替代,而是演进。

Concepts 解决了 SFINAE 的哪些痛点

SFINAE 虽然可行,但写起来绕、读起来晦涩、错起来难懂:

  • 约束逻辑藏在函数重载或 enable_if 的模板参数里,和语义意图脱节;
  • 错误信息中充斥着冗长的 substitution failure 堆,真正的问题(比如 “T 没有 operator
  • 无法对概念本身命名复用,相同约束(如 “可比较”、“可迭代”)需重复写 enable_if + traits;
  • 不支持 concept 检查点提前终止:SFINAE 只在实例化时才触发淘汰,而 Concepts 可在模板声明处就拒绝不满足要求的实参。

SFINAE 仍是 Concepts 的底层基础

Concepts 并没有废除 SFINAE,而是构建在其之上:

  • 每个 concept 的定义(如 requires (T t) { t.begin(); t.end(); })在编译器内部仍会触发表达式替换,失败时仍走 SFINAE 规则;
  • 使用 concept 限定的函数模板(如 template void f(I&))在重载解析阶段,不满足 concept 的类型会被 SFINAE 排除;
  • 你依然可以在 concept 内部使用 std::is_integral_v 等 type traits —— 这些 traits 本身也依赖 SFINAE 实现。

从 SFINAE 到 Concepts:一个对比示例

目标:只接受支持 begin()/end() 且元素可打印的容器类型。

立即学习C++免费学习笔记(深入)”;

● SFINAE 写法(C++14):

造好物
造好物

一站式AI造物设计平台

下载
template
auto print_range(T&& r) -> decltype(std::cout << *r.begin(), void()) {
  for (auto& x : r) std::cout << x << ' ';
}

问题:约束混在返回类型里,不可读;报错时提示 “no match for operator

● Concepts 写法(C++20):

template
concept PrintableRange = requires(T& r) {
  r.begin(); r.end();
  requires std::same_as;
};

template
void print_range(R&& r) {
  for (auto& x : r) std::cout << x << ' ';
}

优势:约束显式、可命名、可组合;错误信息直指 “type X does not satisfy PrintableRange”,并列出具体缺失要求。

不是非此即彼:它们可以共存

实际项目中常见混合使用:

  • 用 Concepts 做顶层约束(清晰意图),内部仍用 SFINAE 或 traits 做细粒度检测;
  • 为兼容旧代码,用 requires 替代部分 enable_if,逐步迁移;
  • 某些高级元编程场景(如延迟 SFINAE、constexpr 分支选择),SFINAE 仍有不可替代性。

基本上就这些。Concepts 不是推翻 SFINAE,而是把过去靠技巧拼凑的约束,变成语言一级的、可读可维护的契约表达。

相关专题

更多
scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

187

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

271

2023.10.25

javascriptvoid(o)怎么解决
javascriptvoid(o)怎么解决

javascriptvoid(o)的解决办法:1、检查语法错误;2、确保正确的执行环境;3、检查其他代码的冲突;4、使用事件委托;5、使用其他绑定方式;6、检查外部资源等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

175

2023.11.23

java中void的含义
java中void的含义

本专题整合了Java中void的相关内容,阅读专题下面的文章了解更多详细内容。

97

2025.11.27

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1018

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

62

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

402

2025.12.29

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

388

2023.07.18

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

4

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号