概念的使用
了解 C++ 概念的主要应用场景。
概念是C++20引入的主要新特性之一。概念是对模板的扩展,允许程序员直接表达其意图。根据C++之父本贾尼·斯特劳斯特鲁普的说法:“概念使模板如最初设想的那样变得完整。”
C++概念可以在哪些地方使用?
-
我们可以使用概念通过布尔谓词对模板参数进行编译时验证。检查在调用点执行,因此错误信息比以往在实例化时出现时更加清晰易懂。
-
我们还可以基于类型属性实现函数分派。
-
通过概念,我们可以同时要求语法和语义条件。在语法要求方面,想象一下可以强制任何类的API中存在某些特定函数。例如,我们可以创建一个名为
Car的概念,要求其必须包含accelerate函数,如下代码所示。
1#include<concepts> 2template<typename C> 3concept Car = requires(C car) { 4 car.accelerate(); 5};
在本课程中,我们主要会遇到仅包含少量要求的例子。尽管目前尚无编写优质概念的最佳实践(因为这是一个较新的特性),但C++社区已达成共识:好的概念不应规定最少数量的要求;它们必须满足所有条件。这是为了确保我们不会无意中创建出偶然满足的概念。
如果我们能以语义上一致的方式完整地建模某个概念,最终将得到更广泛可用的概念。如果第一次尝试未能达到这一目标,也完全没问题。我们终会做到!
不过需要说明的是,在本课程中,我们通常会看到一些不完整的概念,以便专注于它们的特定部分。
语法要求
我们放在 requires 子句中的任何内容都描述了用于建模概念的类型的语法要求。
课程后续将详细讨论其语法。
语义要求
概念不仅表达语法要求,还表达语义要求。但必须承认,C++概念无法直接表达所有语义要求,至少目前还不能。
一些语义要求与数学公理相关,比如结合律或交换律。
1a + b == b + a // 交换律 2(a + b) + c == a + (b + c) // 结合律
这些可以通过代码来表达。事实上,我们已经部分实现了这一点。
而像操作的时间或空间复杂度这类要求,则无法用代码表达。我们必须依赖代码注释或库文档来说明。
如果想寻找示例,值得查看标准库。例如 std::equality_comparable。
注意:你可以在官方C++文档中了解更多关于
std::equality_comparable概念的信息。
它要求:
- 传入类型的两个相等比较运算符具有交换性。
==运算符具有对称性、传递性和自反性。- 当且仅当对于任意类型为
const std::remove_reference_t<T>的值 t 和任意类型为const std::remove_reference_t<U>的值 u,以及当 C 为std::common_reference_t<const std::remove_reference_t<T>&, const std::remove_reference_t<U>&>*时,满足bool(t == u) == bool(C(t) == C(u)),才定义equality_comparable_with<T, U>。