返回 播客 学习 audios

C++概念(Concepts)的历史、挑战与实现

本期节目深入探讨C++中概念(Concepts)的设计初衷、发展历程与实现现状。从1987年模板设计时的三大目标,到C++11未能引入的遗憾,再到如今在Clang和GCC中的可用性,嘉宾详细解释了概念如何解决泛型编程中的类型约束问题,并分享了标准化过程中的曲折故事。

C++概念泛型编程
成长分 / 100 70 综合收获、行动、留存与影响

为什么值得读本期节目深入探讨C++中概念(Concepts)的设计初衷、发展历程与实现现状

从1987年模板设计时的三大目标,到C++11未能引入的遗憾,再到如今在Clang和GCC中的可用性,嘉宾详细解释了概念如何解决泛型编程中的类型约束问题,并分享了标准化过程中的曲折故事

关键洞察
  1. 这条内容的价值在于把外部信息转化为可执行的判断和行动。
转成行动

Lex Fridman · 中文播客

查看原视频 ↗

节目文字稿

中文播客全文

Podcast Script (zh)

[0.120-10.336] SPEAKER_02: 这个概念的想法给参数化加了限制,我也不确定它是否存在过。 即使曾经可用,它也会限制参数化。 本质上就是可以参数化。

[10.636-16.882] SPEAKER_01: 让我解释一下。 对,十年前还没有。 过去四五年里,我们有了实际可用的版本。

[16.962-23.208] SPEAKER_01: 这是Gabby、Andrew和我一起设计的。 当时我们在德克萨斯州做教授和博士后。

[23.288-31.414] SPEAKER_01: 安德鲁·萨顿的实现一直可用,现在成了C++的一部分。 还有一个标准库用到了它。 所以这越来越真实了。

[31.494-44.139] SPEAKER_01: 它在Clang和GCC里已经用了好几年,微软应该也快跟进了。 我们期望C++20的功能在2020年前都能在主流编译器里用上。 但这东西嘛……

[44.219-52.438] SPEAKER_01: 现在已经能用了。 我这么说,不然大家以为我在讲科幻。 所以我说的是具体的。 你今天就能跑起来。 所以我说的是具体的。

[52.518-63.431] SPEAKER_01: 你今天就能跑起来。 而且它有实际用途。 基本思路:有个通用组件,比如排序函数, 排序函数至少需要两个参数。

[63.511-72.067] SPEAKER_01: 第一个, 一个特定类型的数据结构。 还有一个比较标准。 这些是相关的,但如果你不知道 你要比较的东西的类型。

[72.147-85.861] SPEAKER_01: 所以你想说,我要排序某物,它要可排序。 可排序是什么意思? 你查标准。 它必须有开头和结尾的序列。 它必须有… 它必须有开头和结尾。 必须能随机访问该序列。

[85.941-91.084] SPEAKER_01: 并且必须有… 元素类型默认能用小于号比较。 意味着小于号能用。

[91.384-91.836] SPEAKER_02: 对。

[92.136-107.997] SPEAKER_01: 小于运算符能操作。 简单说,就是编译时的判断条件。 这些是你可以问的,比如:你是序列吗? 是的。 我有开始和结束。 你是随机访问序列吗? 是的。 我支持下标和加法。

[108.077-122.859] SPEAKER_01: 你的元素类型能比较小于吗? 是的。 我有小于比较,这是结束。 基本上就是这个系统。 不再说接受任意类型,而是说接受某样东西。 它是可排序且明确的。

[122.939-132.377] SPEAKER_01: 你说,好,可以用小于排序。 我不要小于。 我要大于或自己定义的东西。 两个参数:可排序元素和比较准则。

[132.457-141.942] SPEAKER_01: 比较准则会说,需要操作在元素类型上。 在元素类型上,有比较操作。 这就是最基础的东西。 它是编译时的谓词。

[142.022-149.162] SPEAKER_01: 你有我需要的属性吗? 所以它指定了代码的要求。 好。 还有它获取的参数代码。 其实它跟类型很像。

[149.462-152.666] SPEAKER_02: 但运作在概念空间里。 概念。

[152.966-167.736] SPEAKER_01: “概念”这个词是Alex Stefanov用的,他可以说是泛型编程之父。 在C++的背景下。 其他地方也用这个词,但我们叫泛型编程的方式是。 Alex的方式。

[167.816-176.314] SPEAKER_01: 他称之为概念,因为他说它们是某个领域的基本概念。 一个领域的基本概念。 所以就该叫概念。 我们一直都有概念。

[176.394-187.214] SPEAKER_01: 你看K&R写C那本书,C有算术类型和整数类型。 书里就是这样说的。 然后列出它们有哪些,以及它们有某些属性。 今天的区别。 好的。

[187.294-194.376] SPEAKER_01: 比如你写一个概念,它会问:你是整型吗? 你有成为整型的条件吗? 有加减除这些操作吗?

[194.676-202.477] SPEAKER_02: 所以概念的故事是这样:我原以为它在C++11或更早的版本里。 不管当时叫啥。 什么是... 为什么没成功?

[202.557-212.994] SPEAKER_02: 聊聊这个迷人的标准化过程,我觉得很有趣。 我觉得很有意思。 但为什么这么久? 概念有哪些形式? 挑战是什么? 回到87年左右。

[213.294-216.579] SPEAKER_01: 1987? 哇。

[216.879-222.846] SPEAKER_02: 87年左右设计模板时,我想表达模板对参数的要求。

[223.146-230.971] SPEAKER_01: 于是我研究了这点。 模板对参数需要的概念。 然后我就看了看。 我要的模板有三个特点。

[231.051-237.854] SPEAKER_01: 第一,要非常灵活。 得能表达我想不到的东西。 我总被困在只能做某事的语言里。

[237.934-248.115] SPEAKER_01: 设计者说,好吧,我不想那样做。 第二,速度要快,赶上甚至超过手写代码。 如果我有T类型向量和char向量,它应该跑得

[248.195-253.338] SPEAKER_01: 和你手动写char向量一样快。 第三,要能表达约束。

[253.418-261.742] SPEAKER_01: 对参数做接口类型检查。 那时没人知道怎么同时做到这三点。 对我来说,C++必须满足前两个。

[261.822-275.060] SPEAKER_01: 否则就不是C++了。 这困扰了我几十年,第三个问题一直解决不了。 我是那个引入函数参数类型检查的人。 是的。 我把类型检查带进了C语言。我知道好接口的价值。

[275.140-283.603] SPEAKER_01: 这个想法不是我发明的,很常见,但我做到了。 当然,我也想对模板做同样的事,但做不到。 所以这让我很苦恼。

[283.683-294.700] SPEAKER_01: 然后我们再次尝试,2002、2003年,我分析问题并解释可能的原因。 并提出了解决方案。 这不是一个完整的设计。

[294.780-304.323] SPEAKER_01: 我在印第安纳大学有个小组,是我一位老朋友。 他们在印第安纳启动了一个项目,预计两三年内能有一套不错的概念体系。

[304.403-326.812] SPEAKER_01: 那本可以让C++11变成C++06或08。 我的意思是,这系统非常复杂。 这不是个复杂的东西,但概念非常复杂。 意思是,考虑数据的话,几年内你也许已经在另一边实现了许多。 很多事情。 但概念非常复杂。 结果证明我们很多基本想法都错了。 这些太传统了。

[326.892-343.241] SPEAKER_01: 我觉得它们不太适合C++,不能很好处理隐式转换和混合类型算术。 以及混合类型计算,很多来自社区。 那个社区处理类型的方式和C++不同,对你表达的内容有更多限制。

[343.321-349.961] SPEAKER_01: 并且没有严苛的性能要求。 我们尝试了,非常努力,取得了一些成功,但就在...

[350.041-362.254] SPEAKER_01: 限制了你能表达的内容,且没有严苛的性能要求。 我们尝试了,非常努力,取得了一些成功,但只是... 其实还没结束。

[362.334-370.135] SPEAKER_01: 编译慢,难用,除非你 有超越当时技术的优化器。 现在还是这样。 所以我们只能另想办法。

[370.215-378.574] SPEAKER_01: 简单说,一组参数定义操作,你通过 一张间接表。 就跟虚函数一样。 然后你优化间接性来提升性能。

[378.654-380.848] SPEAKER_01: 但我们没法做到。

[381.148-385.559] SPEAKER_02: 就是说,我们有一组参数,如果那是 需要去的地方。

[385.639-393.684] SPEAKER_02: 所以其实我们能行。 于是我们就这么做了。 谢谢你的倾听。 明天见。 再见。 再见。 再见。 再见。 再见啦。 拜拜。 下次见。

[393.764-400.033] SPEAKER_02: 回头聊。 再会哦。 拜拜咯。 后会有期。 先这样啦。 再见咯。 下次再聊。 再见了。 拜拜啦。