1. 所有标准概念的概述
“类型和对象基本概念”表列出了类型和对象的基本概念。
“范围、迭代器和算法概念”表列出了范围、视图、迭代器和算法的概念。
“辅助概念”表列出的概念主要用作其他概念的构建块,通常不会让应用程序开发者直接使用。
头文件和命名空间
标准概念在不同的头文件中定义:
• 头文件<concepts> 中定义了许多基本概念,其中包括<ranges> 和<iterator>。
• 迭代器的概念在头文件<iterator> 中定义。
• 范围的概念在头文件<ranges> 中定义。
• <compare> 中定义了three_way_comparable 的概念(几乎包含在所有其他头文件中)。
• uniform_random_bit_generator 在<random> 中定义。
几乎所有的概念都定义在命名空间std 中,唯一的例外是range 概念,它定义在命名空间
std::ranges 中。
1.1 类型和对象的基本概念
1. 2 辅助概念
1. 3 范围、迭代器和算法的概念
1.4. 标准概念的包含
C++ 标准库提供的概念经过精心设计,以便包含其他概念,其建立了一个相当复杂的包含图。
2.语言相关的概念
2.1 算法概念
std::integral<T>
• 保证类型T 是整型(包括bool 和所有字符类型)。
• 要求:
– 类型特性std::is_integral_v<T> 为true
std::signed_integral<T>
• 保证类型T 是有符号整型(包括有符号字符类型,可能是char)。
• 要求:
– 需要满足std::integral<T>
– 类型特性std::is_signed_v<T> 为true
std::unsigned_integral<T>
• 保证类型T 是无符号整型(包括bool 和无符号字符类型,可能是char)。
• 要求:
– 需要满足std::integral<T>
– 类型特性std::is_signed_v<T> 为true
std::floating_point<T>
• 保证类型T 是浮点类型(float、double 或long double)。
• 引入这个概念是为了能够定义数学常数。
• 要求:
– 类型特性std::is_floating_point_v<T> 为true
2.2 对象概念
对于对象(既不是引用,也不是函数,也不是void 的类型),有一个所需基本操作的层次结构。
std::movable<T>
• 保证类型T 是可移动和可交换的。可以移动构造、移动赋值,以及与该类型的另一个对象交
换。
• 要求:
– 需要满足std::move_constructible<T>
– 需要满足std::assignable_from<T&, T>
– 需要满足std::swappable<T>
– T 既不是引用,也不是函数,也不是void
std::copyable<T>
• 保证类型T 是可复制的(可移动和可交换)。
• 要求:
– 需要满足std::movable<T>
– 需要满足std::copy_constructible<T>
– std::assignable_from 用于任意T,T&,const T,以及const T& 转换为T&
– 需要满足std::swappable<T>
– T 既不是引用,也不是函数,也不是void
std::semiregular<T>
• 保证类型T 是半常规的类型(可以默认初始化、复制、移动和交换)。
• 要求:
– 需要满足std::copyable<T>
– 需要满足std::default_initializable<T>
– 需要满足std::movable<T>
– 需要满足std::copy_constructible<T>
– std::assignable_from 用于任意T,T&,const T,以及const T& 转换为T&
– 需要满足std::swappable<T>
– T 既不是引用,也不是函数,也不是void
std::regular<T>
• 保证类型T 是常规的(可以默认初始化、复制、移动、交换和检查相等性)。
• 要求:
– 需要满足std::semiregular<T>
– 需要满足std::equality_comparable<T>
– 需要满足std::copyable<T>
– 需要满足std::default_initializable<T>
– 需要满足std::movable<T>
– 需要满足std::copy_constructible<T>
– std::assignable_from 用于任意T,T&,const T,以及const T& 转换为T&
– 需要满足std::swappable<T>
– T 既不是引用,也不是函数,也不是void
2.3 概念间的关系类型
std::same_as<T1, T2>
• 保证T1 和T2 类型相同。
• 概念两次调用std::is_same_v 类型特性,以确保与参数的顺序无关。
• 要求:
– 类型特性std::is_same_v<T1, T2> 为true
– 与T1 和T2 的顺序无关
std::convertible_to<From, To>
• 保证From 类型的对象隐式和显式可转换为To 类型的对象。
• 要求:
– 类型特性std::is_convertible_v<From, To> 为true
– 支持从From 到To 的static_cast
– 可以将From 类型的对象作为To 返回
std::derived_from<D, B>
• 保证D 类型是从B 类型公开派生的(或者D 和B 是相同的),D 类型的指针都可以转换为B 类
型的指针。换句话说: 保证了D 引用/指针可以用作B 引用/指针。
• 要求:
– 类型特性std::is_base_of_v<B, D> 为true
– 对于类型D 到B 的const 指针,类型特性std::is_convertible_v 为true
std::constructible_from<T, Args...>
• 保证可以用Args…类型的参数初始化一个T 类型的对象。
• 要求:
– 需要满足std::destructible<T>
– 类型特性std::is_constructible_v<T, Args...> 为true
std::assignable_from<To, From>
• 保证可以将From 类型的值移动或复制赋值给To 类型的值。
赋值还必须产生原始To 对象。
• 要求:
– To 必须是一个左值引用
– std::common_reference_with<To, From> 满足类型的const 左值引用
– 必须支持赋值运算符,并产生与To 相同的类型
std::swappable_with<T1, T2>
• 保证类型T1 和T2 的值可以交换。
• 要求:
– 需要满足std::common_reference_with<T1, T2>
– 任意两个T1 和T2 类型的对象,都可以通过使用std::ranges::swap() 交换值。
std::common_with<T1, T2>
• 保证类型T1 和T2 共享一个可以显式转换为的公共类型。
• 要求:
– 类型特性std::common_type_t<T1, T2> 会产生一个类型
– 其通用类型支持static_cast
– 这两种类型的引用共享一个common_reference 类型
– 与T1 和T2 的顺序无关
std::common_reference_with<T1, T2>
• 保证类型T1 和T2 共享一个common_reference 类型,可以显式和隐式地转换为该类型。
• 要求:
– 类型特性std::common_reference_t<T1, T2> 会产生一个类型
– 这两种类型可通过std::convertible_to 转换为公共引用类型
– 与T1 和T2 的顺序无关
2.4 比较概念
std::equality_comparable<T>
• 保证类型T 的对象可使用== 和!= 操作符比较,与顺序无关。
• T 的== 操作符应该是对称的和可传递的:
– 当t2==t1 时,t1==t2 为真
– 若t1==t2 和t2==t3 为真,则t1==t3 为真
但这是在编译时无法检查的语义约束。
• 要求:
– == 和!= 操作符都受支持,并产生可转换为bool 的值
std::equality_comparable_with<T1, T2>
• 保证类型T1 和T2 的对象可以使用== 和!= 操作符进行比较。
• 要求:
– 对于涉及T1 和/或T2 对象的所有比较,都支持== 和!=,并产生可转换为bool 的相同类
型的值
std::totally_ordered<T>
• 保证类型T 的对象可与==、!=、<、<=、> 和>= 操作符进行比较,以便两个值总是相互等于、
小于或大于对方。
• 这个概念并没有声称类型T 具有所有值的总顺序,即使浮点值没有顺序,但表达式
std::totally_ordered<double> 的结果仍然为true:
1 std::totally_ordered<double> // true
2 std::totally_ordered<std::pair<double, double>> // true
3 std::totally_ordered<std::complex<int>> // false
提供这个概念是为了检查能够对元素进行排序的正式需求,因使用了std::ranges::less,这是排
序算法的默认排序条件。若类型没有所有值的总顺序,排序算法就不会编译失败,支持所有
六个基本比较运算符就足够了。要排序的值应该是全序或弱序,但这是在编译时无法检查的
语义约束。
• 要求:
– 需要满足std::equality_comparable<T>
– 与==、!=、<、<=、> 和>= 操作符的所有比较都会产生可转换为bool 的值
std::totally_ordered_with<T>
• 保证类型T1 和T2 的对象与==、!=、<、<=、> 和>= 操作符具有可比性,以便两个值总是相
互等于、小于或大于对方。
• 要求:
– 对于涉及T1 和/或T2 对象的所有比较,都支持==,!=,<,<=,> 和>= 操作符,并产生
可转换为bool 的相同类型的值
std::three_way_comparable<T>, std::three_way_comparable<T, Cat>
• 保证类型T 的对象与==、!=、<、<=、>、>= 和<=> 操作符可比较(并且至少具有比较类别类
型Cat)。若没有传递Cat,则需要std::partial_ordering。
• 这个概念在头文件<compare> 中定义。
• 注意,这个概念并不包含std::equality_comparable,因为后者要求== 操作符只对两个相等的
对象产生真值。对于弱序或偏序,情况可能不是这样。
• 注意, 这个概念并不暗示和包含std::totally_ordered, 因为后者要求比较类别是
std::strong_ordering 或std::weak_ordering。
• 要求:
– 与==、!=、<、<=、> 和>= 操作符的所有比较都会产生可转换为bool 的值
– 与<=> 操作符的任何比较都会产生一个比较类别(至少是Cat)。
std::three_way_comparable_with<T1, T2>, std::three_way_comparable_with<T1, T2, Cat>
• 保证任意两个T1 和T2 类型的对象都可以与==、!=、<、<=、>、>= 和<=> 操作符进行比较
(并且至少具有比较类别类型Cat)。若没有传递Cat,则需要std::partial_ordering。
• 这个概念在头文件<compare> 中定义。
• 注意,这个概念并不包含std::equality_comparable_with,因为后者要求== 操作符只对两个相
等的对象产生真值。对于弱序或偏序,情况可能并不是这样。
• 注意, 这个概念并不暗示和包含std::totally_ordered_with, 因为后者要求比较类别是
std::strong_ordering 或std::weak_ordering。
• 要求:
– std::three_way_comparable 满足T1 和T2(以及Cat) 的值和公共引用
– 与==、!=、<、<=、> 和>= 操作符的所有比较都会产生可转换为bool 的值
– 与<=> 操作符的任何比较都会产生一个比较类别(至少是Cat)。
– 与T1 和T2 的顺序无关