赞
踩
约束与概念是C++20中最新引入的核心语言特性。约束(constraint)可以关联到类模板、函数模板、类模板成员函数,指定了对模板实参的一些要求,这些要求可以被用于选择最恰当的函数重载和模板特化。概念(concept) 是这些要求(即约束)的集合。
语法:
- template < 模板形参列表 >
- concept 概念名 = 约束表达式;
例子:
- template<class T, class U>
- concept isChildOf = std::is_base_of<U, T>::value;//类型约束, T必须继承自U
-
-
- /***
- 使用概念
- 注意:概念在类型约束中接受的实参要比它的形参列表要求的要少一个,
- 因为按语境推导出的类型会隐式地作第一个实参
- ***/
- template<isChildOf<Base> T>
- void f(T); // T 被 isChildOf<T, Base> 约束
组成概念的约束表达式也可以用requires字句定义:
- //以下代码摘自cppreference: https://en.cppreference.com/w/cpp/language/constraints
-
- #include <concepts>
-
- // 概念 "Hashable" 的声明可以被符合以下条件的任意类型 T 满足:
- // 对于 T 类型的值 a,表达式 std::hash<T>{}(a) 可以编译并且它的结果可以转换到 std::size_t
- template<typename T>
- concept Hashable = requires(T a)
- {
- { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
- };
-
- //在函数模板中使用概念
- template<Hashable T>
- void f(T); // 受约束的 C++20 函数模板
也可以按如下格式使用概念:
- template<typename T> requires Hashable<T> //requires子句放在template<>之后
- void f(T)
- {
- //...
- }
-
- template<typename T>
- void f(T) requires Hashable<T> //requires子句放在函数参数列表之后
- {
- //...
- }
注意:
概念本身不能被约束,概念不能被递归定义。
- //以下代码摘自cppreference: https://en.cppreference.com/w/cpp/language/constraints
- template<typename T>
- concept V = V<T*>; // 错误:递归的概念
-
- template<class T>
- concept C1 = true;
- template<C1 T>
- concept Error1 = true; // 错误:C1 T 试图约束概念定义
- template<class T> requires C1<T>
- concept Error2 = true; // 错误:requires 子句试图约束概念
在这种情况下,requires后面必须跟随一个常量表达式,或者满足如下形式的requires表达式:
&&
联结的初等表达式的序列||
联结的前述表达式的序列- template<class T>
- constexpr bool is_meowable = true;
-
- template<class T>
- constexpr bool is_purrable() { return true; }
-
- template<class T>
- void f(T) requires is_meowable<T>; // OK
-
- template<class T>
- void g(T) requires is_purrable<T>(); // 错误:is_purrable<T>() 不是初等表达式
-
- template<class T>
- void h(T) requires (is_purrable<T>()); // OK
此时,requires表达式是bool类型的纯右值表达式,描述对一些模板实参的约束。这种表达式在约束得到满足时是true,否则是false,比如下面的代码:
- template<typename T>
- concept Addable = requires (T x) { x + x; }; // requires 表达式
-
- template<typename T> requires Addable<T> // requires 子句,不是 requires 表达式
- T add(T a, T b) { return a + b; }
-
- template<typename T>
- requires requires (T x) { x + x; } // 随即的约束,注意关键字被使用两次
- T add(T a, T b) { return a + b; }
require表达式具有如下语法:
- requires { 要求序列 }
- requires ( 形参列表(可选) ) { 要求序列 }
其中,要求序列根据复杂程度可以分为以下四种:
- // 简单要求
- template<typename T>
- concept Addable = requires (T a, T b)
- {
- a + b; // “表达式 a + b 是可编译的合法表达式”
- };
-
- // 类型要求
- template<typename T>
- using Ref = T&;
-
- template<typename T>
- concept C = requires
- {
- typename T::inner; // 要求的嵌套成员名
- typename S<T>; // 要求的类模板特化
- typename Ref<T>; // 要求的别名模板替换
- };
-
- // 嵌套要求
- template <class T>
- concept Semiregular = DefaultConstructible<T> &&
- CopyConstructible<T> && Destructible<T> && CopyAssignable<T> &&
- requires(T a, size_t n)
- {
- requires Same<T*, decltype(&a)>; // 嵌套:“Same<...> 求值为 true”
- { a.~T() } noexcept; // 复合:"a.~T()" 是不抛出的合法表达式
- requires Same<T*, decltype(new T)>; // 嵌套:“Same<...> 求值为 true”
- requires Same<T*, decltype(new T[n])>; // 嵌套
- { delete new T }; // 复合
- { delete new T[n] }; // 复合
- };
复合要求有自己的语法,因此我们将它单列出来,其语法形式为:
- { 表达式 } noexcept(可选) 返回类型要求(可选) ;
- 返回类型要求 -> 类型约束
例子:
- // 复合要求
- template<typename T>
- concept C2 = requires(T x)
- {
- // 表达式 *x 必须合法
- // 并且类型 T::inner 必须合法
- // 并且 *x 的结果必须可以转换为 T::inner
- {*x} -> std::convertible_to<typename T::inner>;
-
- // 表达式 x + 1 必须合法
- // 并且 std::Same<decltype((x + 1)), int> 必须被满足
- // 也就是说,(x + 1) 必须是 int 类型的纯右值
- {x + 1} -> std::same_as<int>;
-
- // 表达式 x * 1 必须合法
- // 并且它的结果必须可以转换到 T
- {x * 1} -> std::convertible_to<T>;
- };
当编译器在进行模板函数的重载决议时,会选择更受约束的版本
- template<typename T>
- concept Decrementable = requires(T t) { --t; };
- template<typename T>
- concept RevIterator = Decrementable<T> && requires(T t) { *t; };
-
- // RevIterator 能归入 Decrementable,但反之不行
-
- template<Decrementable T>
- void f(T); // #1
-
- template<RevIterator T>
- void f(T); // #2,比 #1 更受约束
-
- f(0); // int 只满足 Decrementable,选择 #1
- f((int*)0); // int* 满足两个约束,选择 #2,因为它更受约束
本文只是列举了“概念”,“约束”等新特性的表面用法,笔者自身水平还不能做更深入讨论,如有遗漏,欢迎广大网友补充,批评指正。
本文参考自:Constraints and concepts (since C++20) - cppreference.com
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。