C++的概念和Rust的特征有什么相似之处和不同之处?

2022-05-25 00:00:00 rust traits c++ c++-concepts

在Rust中,抽象的主要工具是特征。在C++中,有两种抽象工具:抽象类和模板。为了摆脱使用模板的一些缺点(例如,难以读取错误消息),C++引入了概念,它们是"named sets of requirements"。

这两个功能似乎非常相似:

  • 定义特征/概念是通过列出需求来完成的。
  • 两者都可用于绑定/限制泛型/模板类型参数。
  • Rust特征和带有概念的C++模板都是单一化的(我知道Rust特征也可以用于动态调度,但那是另一回事)。

但据我所知,也有显著的差异。例如,C++的概念似乎定义了一组必须有效的表达式,而不是列出函数签名。但那里有许多不同和令人困惑的信息(可能是因为概念只出现在C++20中?)。这就是为什么我想知道:C++的概念和Rust的特征到底有什么不同和相似之处?

是否有仅由概念或特征提供的功能?例如,铁锈的相关类型和常量如何?或通过多个特征/概念限制类型?


解决方案

免责声明:我还没有使用过概念,我所知道的所有关于它们的信息都是从各种建议和cp偏好中收集的,所以对这个答案持保留态度。

运行时多态

Rust特征既用于编译时多态,有时也用于运行时多态;概念仅用于编译时多态。

结构与名义。

概念和特征的最大区别在于,概念使用结构类型,而特征使用名义类型:

  • 在C++中,类型从不显式满足某个概念;如果恰好满足所有要求,它可能会"意外"满足该概念。
  • 在Rust中,特定的语法构造impl Trait for Type用于显式指示类型实现了特征。

有许多后果;一般来说,从可维护性的角度来看,名义类型化更好--向特征添加需求--而结构类型化更适合桥接第三方库--库A中的类型可以满足库B中的概念,而它们彼此不知道。

约束

特性是必需的:

  • 如果不需要此类型来实现提供方法的特征,则不能对泛型类型的变量调用任何方法。

概念是完全可选的:

  • 可以在泛型类型的变量上调用方法,而不需要此类型来满足任何概念,也不需要以任何方式进行约束。
  • 可以在满足一个(或多个)概念的泛型类型的变量上调用方法,而无需由任何概念或约束指定该方法。
  • 约束(请参阅备注)可以完全是即席的,并且不使用命名概念来指定要求;同样,它们也是完全可选的。

注意:约束由requires子句引入,并指定临时要求或基于概念的要求。

要求

可表达的要求集不同:

  • 概念/约束通过替换工作,因此允许语言的全部范围;要求包括:嵌套类型/常量/变量、方法、字段、能够用作另一个函数/方法的参数、能够用作另一个类型的泛型参数及其组合。
  • 相比之下,特征只允许一小部分要求:关联的类型/常量和方法。

重载选择

Rust没有即席重载的概念,重载仅由特征发生,还不可能进行专门化。

C++约束可用于按从最不具体到最具体的顺序对重载进行排序,因此编译器可以自动选择满足要求的最具体的重载。

注意:在此之前,在C++中将使用SFINAE或标记调度来实现选择;需要健美操来处理开放式重载集。

析取

我还不太清楚如何使用此功能。

Rust中的要求机制是纯加法的(合取,又名&&),相反,在C++中requires子句可以包含析取(又名||)。

相关文章