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

命途多舛的Concepts:从提出到剔除再到延期最后到纳入,Concepts为什么在C++中大起大落?

在C++的漫长发展史中,Concepts(概念)的故事显得尤为引人注目。它的历程不仅是C++社区技术演进的缩影,也是对软件工程实践的一次深刻反思。本文将详细剖析C++的Concepts:它是什么,它的设计初衷与使用场景,以及为何在C++的历史中经历了如此多的波折。

什么是C++的Concepts?

在深入讨论Concepts的历程之前,我们首先需要明确概念本身。C++的Concepts在C++20标准中正式成为语言的一部分,它们为模板编程引入了一种类型约束系统。Concepts的核心目标是提高模板代码的可读性、可用性,同时让编译器能够提供更准确的错误信息,简化模板元编程的复杂性。

设计初衷

Concepts的设计初衷围绕着几个关键点:

  1. 可读性:通过明确表达模板参数的要求,Concepts使得模板的意图和用法更加直观。
  2. 错误诊断:Concepts允许在编译期进行更深入的类型检查,以便提供具体的错误信息,避免了传统模板错误的晦涩难懂。
  3. 元编程简化:Concepts提供了一种比传统SFINAE(Substitution Failure Is Not An Error,替换失败不是错误)更加简洁和直观的方式来处理模板中的类型约束。

使用场景

Concepts的使用场景广泛,主要包括:

  1. 模板参数类型限制:使用Concepts可以限定传入模板的类型必须符合某些预定义的接口或性能特性。
  2. 函数模板重载:Concepts可以帮助实现基于类型性质的函数模板重载,而不仅仅是基于类型本身。
  3. API设计优化:通过为模板参数定义明确的Concepts,库的设计者可以创建易于理解和使用的接口。

代码例子

以下是一个简单的例子,展示如何使用Concepts来限制函数模板的参数类型:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>// 定义一个可迭代的Concept
template<typename T>
concept Iterable = requires(T x) {std::begin(x);  // 必须支持begin操作std::end(x);    // 必须支持end操作
};// 定义一个可比较的Concept
template<typename T>
concept Comparable = requires(T a, T b) {{ a < b } -> std::convertible_to<bool>;{ a > b } -> std::convertible_to<bool>;
};// 使用定义的Concepts约束模板参数
template<Iterable T, Comparable<typename T::value_type>>
void sort(T& container) {std::sort(std::begin(container), std::end(container));
}int main() {std::vector<int> numbers = {4, 1, 3, 2};sort(numbers);  // 使用sort模板函数排序vectorfor (int num : numbers) {std::cout << num << ' ';}std::cout << std::endl;// 如果尝试传递不满足Iterable或Comparable约束的类型,编译器将报错return 0;
}

在这个例子中,我们定义了两个Concepts:IterableComparable,它们分别约束容器类型必须支持迭代操作,并且容器中的元素必须可以进行比较。然后我们定义了一个sort函数模板,它使用这两个Concepts作为其参数的约束。这样,当sort函数被调用时,如果参数类型不符合这些约束,编译器将提供清晰的错误信息。

提供清晰的错误信息

例如:以下模板代码

template<typename R, typename T>
bool exist(const R& range, const T& value) {
for (const auto& x : range)if (x == value)return true;return false;
}
vector<string> vec {};
exist(vec, 47); // BUG!

在GCC 5.2的报错信息长达180多行。
如果使用Concept 为模板参数增加约束:

template<typename R, typename T>requires Equality_comparable<T, Value_type<R>>()
bool exist(const R& range, const T& value) {for (const auto& x : range)if (x == value)return true;return false;
}
vector<string> vec {};
exist(vec, 47); // BUG!

使用Concept的GCC报错信息只有3行!
在这里插入图片描述

由此可见,Concept为模板提供了更精细的语义。

Concepts的曲折历程

Concepts的历史可以追溯到C++标准化进程的早期阶段。最初,Concepts被提出作为C++0x(即C++11)的一部分,旨在解决长久以来模板编程中的一系列问题。然而,由于实现的复杂性和社区意见的分歧,Concepts最终并未出现在C++11的最终版本中。

从提出到剔除

C++11标准的制定过程中,Concepts的提议受到了广泛关注。许多人认为,Concepts将是C++模板编程的未来。它们为解决模板错误难以诊断、元编程复杂等问题提供了有力的工具。然而,随着标准化工作的深入,Concepts的复杂性逐渐暴露。它们要求对编译器进行大量的修改,给编译器的实现带来了很大的挑战。此外,C++社区中也存在对Concepts复杂性和实用性的争议。

在权衡了这些因素之后,C++标准委员会做出了一个艰难的决定:将Concepts从C++11标准中移除。这一决定在社区中引起了广泛的讨论和反响。一方面,有人认为这是一个明智的选择,因为未熟的特性可能会给语言的未来发展带来负担;另一方面,也有人对此感到失望,因为Concepts被寄予了厚望。

在C++11移除Concept的时候,Michael Wong曾经说过一句话:“I am sure this will not be the last we will hear of it.”

延期与重新审视

尽管Concepts在C++11中未能成行,但它的理念并未被抛弃。在接下来的几年里,Concepts得到了重新设计和精简,社区对于如何在C++中实现类型约束的讨论仍在继续。这一期间,Concepts的思想逐渐成熟,其实现方式也更加清晰。

在C++标准委员会的不懈努力和社区的广泛支持下,Concepts最终在C++20中标准化。这一次,Concepts的设计更加精炼,与C++语言的其他特性更加协调,得到了社区的普遍接受。

Concepts为何大起大落?

Concepts在C++中的大起大落,是C++社区对新特性审慎态度的体现。C++是一个历史悠久且广泛使用的编程语言,任何新特性的加入都必须经过严格的审查,以确保它们不仅在技术上成熟,而且能够解决实际问题,为C++的发展做出实质性贡献。

C++社区在评估新特性时,既重视技术的先进性,也重视实用性和稳定性。这种平衡在Concepts的发展历程中得到了充分体现。Concepts最初的设计被认为过于复杂和笨重,不适合纳入C++11。但随着时间的推移,经过不断的修订和优化,Concepts以一种更加简洁和实用的形式重新回到了C++20标准,这次它以更加成熟的姿态得到了社区的广泛支持。

Concepts的深远影响

Concepts的纳入对C++语言本身以及它的用户群有着深远的影响。首先,它是对C++类型系统的一次显著扩展。它为模板编程带来了先前所没有的类型检查能力和表达能力,使得模板更加安全和易于使用。此外,它还影响了现有库和未来库的设计,因为库的作者现在可以使用Concepts来指定更精确的接口要求。

结语

C++的Concepts代表了语言演进的一种动态平衡。在追求技术卓越的同时,C++社区也在不断地反思和调整,以确保新特性的引入既能够带来实际的好处,也不会过度地增加语言的复杂性。Concepts的故事是一个关于技术、社区以及软件工程实践的故事。从提出到剔除,再到延期最后到纳入,Concepts的经历不仅仅是C++特性史上的一个篇章,它也是对整个编程社区如何前行的一次深刻反思。

随着C++20标准的落地,Concepts开始在实际开发中展现其价值。尽管它的道路并不平坦,但它的终到来临却揭示了C++未来发展的无限可能。让我们期待在Concepts的指引下,C++社区能够继续开创出更加安全、高效、易于理解的编程范式,为全世界的软件开发贡献出自己的力量。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • API接口的作用和应用程序讲解
  • 「3D开发工具」HOOPS如何赋能CAD/AEC/BIM数据转换与可视化?
  • React学习之props(父传子,子传父),Context组件之间的传参。
  • 数据结构之探索“堆”的奥秘
  • 06.java集合
  • JAVAWeb实战(后端篇)
  • Java零基础之多线程篇:多线程最佳实践
  • 【Android】安卓多媒体之通知、摄像头、相册、播放音乐、视频用法总结
  • 收银系统源码-门店折扣活动应该怎么做
  • 你了解渗透测试吗?渗透测试在网络安全行业属于食物链什么层级?
  • vue-创建自己的CLI脚手架
  • 预测性维护:一种基于因果技术语言处理 (CTLP) 的智能故障诊断方法
  • js、ts、argular、nodejs学习心得
  • 研究人员可以采用什么策略来批判性地评估和综合其领域的不同文献
  • SSL组网的概念,SSL组网方式怎么实现
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • axios 和 cookie 的那些事
  • HashMap ConcurrentHashMap
  • Invalidate和postInvalidate的区别
  • Java IO学习笔记一
  • MobX
  • npx命令介绍
  • PHP 的 SAPI 是个什么东西
  • SpingCloudBus整合RabbitMQ
  • 阿里云购买磁盘后挂载
  • 编写符合Python风格的对象
  • 使用iElevator.js模拟segmentfault的文章标题导航
  • 使用SAX解析XML
  • 小试R空间处理新库sf
  • 终端用户监控:真实用户监控还是模拟监控?
  • 最简单的无缝轮播
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • (1) caustics\
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (20)docke容器
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (九)信息融合方式简介
  • (七)Activiti-modeler中文支持
  • (十六)Flask之蓝图
  • (未解决)macOS matplotlib 中文是方框
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (转)大道至简,职场上做人做事做管理
  • (转载)(官方)UE4--图像编程----着色器开发
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .NET Framework 3.5中序列化成JSON数据及JSON数据的反序列化,以及jQuery的调用JSON
  • .net 使用ajax控件后如何调用前端脚本
  • .NET多线程执行函数
  • .NET开源纪元:穿越封闭的迷雾,拥抱开放的星辰
  • .net中应用SQL缓存(实例使用)
  • [].slice.call()将类数组转化为真正的数组
  • [20190113]四校联考
  • [AHK] WinHttpRequest.5.1报错 0x80092004 找不到对象或属性
  • [BZOJ] 2044: 三维导弹拦截
  • [C#]C# winform部署yolov8目标检测的openvino模型