Namespaces
Variants

Concepts library (since C++20)

From cppreference.net

概念库提供了基础库概念的定义,可用于执行模板参数的编译时验证,并根据类型属性进行函数分派。这些概念为程序中的等式推理奠定了基础。

标准库中的大多数概念同时施加了语法要求和语义要求。当一个标准概念的语法要求被满足时,我们称其被 满足 ;若该概念不仅被满足且其语义要求(若存在)也同时达成,则称其被 建模

通常来说,编译器只能检查语法要求。如果程序的有效性或含义取决于模板参数序列是否对概念进行建模,而概念被满足但未建模,或者在使用点未满足语义要求,则程序是非良构的, 不要求诊断

目录

等值保持

一个表达式是 保等性 的,如果它在给定相等输入的情况下产生相等的输出,其中

  • 输入包含其操作数(不必然使表达式在语义上有效),以及
  • 输出包含表达式的结果及对操作数的所有修改(若存在)

此处为表述方便,其"操作数"指代由 标识表达式 std::move std::forward std::declval 调用构成的最大子表达式。

每个操作数的 cv 限定性和值类别通过假定其类型中的每个模板类型参数表示一个 cv 非限定的完整非数组对象类型来确定。

每个要求保持相等性的表达式还必须满足稳定性要求,即:在未显式修改输入对象的情况下,对同一组输入对象进行两次求值必须产生相等的输出结果。

除非另有说明,标准库概念中使用的 requires 表达式 中的每个表达式都必须保持相等性,且表达式的求值只能修改其非常量操作数。常量操作数不得被修改。

在标准库中,以下概念允许包含非保序的 requires 表达式:

隐式表达式变体

一个 requires 表达式 若对某个常量左值操作数使用非修改性表达式,则除非已显式要求具有不同语义的表达式变体,否则该表达式还会隐式要求接受非常量左值或(可能为常量的)右值作为给定操作数的额外表达式变体。

这些 隐式表达式变体 必须满足与声明表达式相同的语义要求。实现对于这些变体语法验证的程度未作规定。

template<class T>
concept C = requires(T a, T b, const T c, const T d)
{
    c == d;           // 表达式 #1:不修改操作数
    a = std::move(b); // 表达式 #2:修改两个操作数
    a = c;            // 表达式 #3:修改左操作数 `a`
};
// 表达式 #1 隐式要求满足 c == d 要求(包括非修改性)的额外表达式变体,
// 如同以下表达式也已被声明:
// ------ const == const ------- ------ const == non-const ---
//                                         c  ==           b;
//            c == std::move(d);           c  == std::move(b);
// std::move(c) ==           d;  std::move(c) ==           b;
// std::move(c) == std::move(d); std::move(c) == std::move(b);
// -- non-const == const ------- -- non-const == non-const ---
//           a  ==           d;            a  ==           b;
//           a  == std::move(d);           a  == std::move(b);
// std::move(a) ==           d;  std::move(a) ==           b;
// std::move(a) == std::move(d); std::move(a) == std::move(b);
// 表达式 #3 隐式要求满足 a = c 要求
// (包括不修改第二个操作数)的额外表达式变体,
// 如同表达式 a = b(非常量左值变体)
// 和 a = std::move(c)(常量右值变体)已被声明。
// 注意:由于表达式 #2 已显式要求非常量右值变体
// (a == std::move(b)),表达式 #3 不再隐式要求该变体。
// 类型 T 满足上述概念 C 显式陈述的语法要求,
// 但不满足额外的隐式要求
// (即 T 满足但不建模 C):
// 要求 C<T> 的程序是非良构的(不要求诊断)。
struct T
{
    bool operator==(const T&) const { return true; }
    bool operator==(T&) = delete;
};

标准库概念

定义于命名空间 std
核心语言概念
定义于头文件 <concepts>
(C++20)
指定一个类型与另一个类型相同
(概念)
指定一个类型派生自另一个类型
(概念)
指定一个类型可隐式转换为另一个类型
(概念)
指定两个类型共享一个公共引用类型
(概念)
指定两个类型共享一个公共类型
(概念)
(C++20)
指定一个类型是整数类型
(概念)
指定一个类型是带符号整数类型
(概念)
指定一个类型是无符号整数类型
(概念)
指定一个类型是浮点类型
(概念)
指定一个类型可从另一个类型赋值
(概念)
指定一个类型可交换或两个类型可相互交换
(概念)
指定该类型的对象可被销毁
(概念)
指定该类型的变量可从一组实参类型构造或绑定
(概念)
指定一个类型的对象可被默认构造
(概念)
指定一个类型的对象可被移动构造
(概念)
指定一个类型的对象可被复制构造和移动构造
(概念)
比较概念
定义于头文件 <concepts>
 (C++20)
指定类型可用于布尔上下文
( 仅用于说明的概念* )
指定运算符 == 是等价关系
(概念)
指定该类型的比较运算符产生全序
(概念)
定义于头文件 <compare>
指定运算符 <=> 在给定类型上产生一致结果
(概念)
对象概念
定义于头文件 <concepts>
(C++20)
指定一个类型的对象可被移动和交换
(概念)
(C++20)
指定一个类型的对象可被复制、移动和交换
(概念)
指定一个类型的对象可被复制、移动、交换和默认构造
(概念)
(C++20)
指定类型是正规的,即同时满足 semiregular equality_comparable
(概念)
可调用概念
定义于头文件 <concepts>

更多概念可在 迭代器库 算法库 以及 范围库 中找到。

参见