通过定义 concepts,可以为一个或多个约束引入名称。
模板(函数、类和变量模板)可以使用 concepts 来约束它们的能力(通过require子句或作为模板形参的直接类型约束)。然而,concepts 也是布尔编译时表达式(类型谓词),您可以在必须检查类型的任何地方使用(例如在if constexpr条件中)。
定义 concepts
concepts定义如下:
template<...>
concept name =..;
等号是必需的(你不能声明一个concepts而不定义它)。
在等号后面,可以指定任何转换为true或false的编译时表达式
concepts很像类型为boo1的constexpr变量模板,但是没有显式地指定类型
template<typename T>
concept MyConcept=;
std::is_same<MyConcept<...>,bool>
这意味着,在编译时或运行时,您总是可以在需要布尔表达式值的地方使用一个concepts。
但是,您不能接受该地址,因为它后面没有对象(它是一个prvalue)。
模板参数可能没有约束(不能使用一个concepts来定义一个concepts)。
你不能在函数内部定义concepts(所有模板都是这样)。
concepts 的特殊能力
concepts具有特殊的能力。如果你比较布尔变量模板的通常定义(因为它特别用于定义类型特征)
template<typename T>
inline constexpr bool IsOrHasThisOrThat =...;
一个concepts的定义
template<typename T>
concept IsOrHasThisOrThat =...;
我们有以下区别:
-
concepts并不代表代码。它们没有类型、存储空间、生命周期或与对象相关的任何其他属性。通过在编译时为特定的模板参数实例化它们,它们的实例化只会变成true或false。因此,你可以在任何你可以使用真或假的地方使用它们,你可以得到这些字面量的所有属性。 -
concepts不必声明为内联的,它们隐式地声明为内联。 -
concepts可以用作类型约束:template<IsOrHasThisOrThat T>变量模板不能这样使用。
-
concepts是给约束命名的唯一方法,这意味着您需要它们来决定是否使用约束
使用concepts作为类型约束
如前所述,concepts可以用作类型约束。
类型约束可以在不同的地方使用:
-
在模板类型参数的声明中
-
在用auto声明的调用参数的声明中
-
在复合需求中的As需求中
例子:
template<std::integral T>
class MyClass {
...
};
auto myFunc(const std::integral auto& val) {
...
};
template<typename T>
concept MyConcept = requires(T x) {
{x+x}→>std::integral;
};
在这里,我们使用为表达式返回的单个参数或类型调用的一元约束。
具有多个参数的类型约束
还可以使用带有多个参数的约束,然后将参数类型或返回值用作第一个参数
template<std::convertible_to<int> T>
class MyClass {
};
auto myFunc(const std::convertible_to<int> auto& val) {
...
};
template<typename T>
concept MyConcept = requires(Tx){
{x+x}-> std::convertible_to<int>;
};
另一个经常使用的例子是约束可调用对象(函数、函数对象、lambda)的类型,要求您可以使用std::invocable或std::regular invocable:例如,要要求传递一个接受int和std::string的操作,你必须声明
template<std::invocable<int, std::string> Callable>
void call(Callable op);
或者:
void call(std::invocable<int, std::string> auto op);
std::invocable和std::regular invocable之间的区别在于后者保证不修改传递的操作和参数。
这是语义上的差异,它只有助于记录意图。通常只使用std::invocable。
类型约束和auto
类型约束可以在所有可以使用 auto 的地方使用:
-
要约束声明,请执行以下操作:
std::integral auto val1 =42; std::integral auto val2 = true; for (const std::integral auto& elem : coll) { ... } -
要约束返回类型,请执行以下操作:
std::integral auto foo() { ... } -
约束非类型模板参数:
template<typename T, std::integral auto max> class SizedColl { ... }; -
这也适用于带有多个参数的
conceptstemplate<typename T, std::convertible_to<T> auto default> class MyType { ... };
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情”