关于C++20Concept(概念)及requires表达式的学习
Concept(概念)
C++20 引入了 concept 以在编译期检查模板实参是否满足指定的约束.
如何不用concept进行约束
template <typename T>
T inc(T& a) {
static_assert(std::is_integral<T>::value);
return ++a;
}
如果使用double a; inc(a);
运行时就会报错(和assert差不多)
虽然可以解决问题,但是T的检查是在函数内实现的,调用时出错了,用户才知道。不能从函数inc的声明直观看出T的要求。而concept会直接报错
//c++ concepts库内对整型的类型限制
template <typename T>
concept integral = std::is_integral<T>::value;
写法
以下展示四种写法(关于requires表达式,稍后再讲)
template <integral T>
T inc(T& a) { return ++a; }
integral auto inc(integral auto a) { return ++a; }
template <typename T>
T inc(T a) requires integral<T> { return ++a; }
template <typename T>
requires integral<T>
T inc(T a) { return ++a; }
关于concept的逻辑运算
依然是concepts库内的约束
template <typename _Tp>
concept signed_integral = integral<_Tp> && is_signed_v<_Tp>;
template <typename _Tp>
concept unsigned_integral = integral<_Tp> && !signed_integral<_Tp>;
requires表达式
requires { requirement-seq }
requires ( parameter-list(optional) ) { requirement-seq }
requirements-seq
可以是:简单要求、类型要求、复合要求、嵌套要求.
简单要求
它可以是任意不以 requires
关键字开头的表达式,它断言该表达式是有效的. 只在语言层面上检查该表达式是否有效(编译通过即可),而不会对该表达式进行求值
template <typename T>
concept Addable = requires(T a, T b) { a + b; }; // a + b 可通过编译即可
类型要求
类型要求是以typename
关键字开始的要求,紧跟typename
的是一个类型名,通常可以用来检查嵌套类型、类模板以及别名模板特化的有效性。如果模板实参替换失败,则要求表达式的计算结果为false
template <typename T, typename T::type = 0>
struct S;
template <typename T>
using Ref = T&;
template <typename T> concept C = requires
{
typename T::inner; // 要求嵌套类型
typename S<T>; // 要求类模板特化
typename Ref<T>; // 要求别名模板特化
};
template <C c>
struct M {};
struct H {
using type = int;
using inner = double;
};
M<H> m;
概念C
中有3个类型要求,分别为T::inner、S<T>
和Ref<T>
,它们各自对应的是对嵌套类型、类模板特化和别名模板特化的检查。请注意代码中的类模板声明S,它不是一个完整类型,缺少了类模板定义。但是编译器仍然可以编译成功,因为标准明确指出类型要求中的命名类模板特化不需要该类型是完整的。
复合要求
template <class T>
concept Check = requires(T a, T b) {
{ a.clear() } noexcept; // 支持clear,且不抛异常
{ a + b } noexcept->std::same_as<int>; // std::same_as<decltype((a + b)), int>
};
template <typename T>
concept C =
requires(T x) {
{*x}; // *x有意义
{ x + 1 } -> std::same_as<int>; // x + 1有意义且std::same_as<decltype((x + 1)), int>,即x+1是int类型
{ x * 1 } -> std::convertible_to<T>; // x * 1 有意义且std::convertible_to< decltype((x *1),T>,即x*1可转变为T类型
};
嵌套要求
由若干条requires构成,每一条都需要满足。
template <class T>
concept Check = requires(T a, T b) {
requires std::same_as<decltype((a + b)), int>;
};
等同于:
template <class T>
concept Check = requires(T a, T b) {
{ a + b } -> std::same_as<int>;
};
参考资料
C++20学习:concept用法介绍_chaos-god的博客
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/283000.html