概念与约束
C++20引入了概念和约束的概念,用于限定模板类型实参的范围
新增了两个关键字concept与requires用于实现要求
requires
requires表达式
1
2
3
4
5
6
requires(Type1 para1, Type2 para2, ...){
要求1;
要求2;
...
要求n;
}require可以有0-n个参数,大括号内有0-n个表达式
require表达式是常量表达式,编译时求值,依次对要求进行判断,遇到第一个无效表达式时返回false,若所有表达式都是有效或良构的,返回true
注意:每条要求不会被实例化或求值,仅用于判断有效
例1:
1
2
3
4
5
6
7
8
9
10
11
12
template <typename T>
bool isAddable(T a, T b){
bool result =
requires(T a, T b){
a+b;
a++;
a+=b;
++a;
{a*1}->std::convertible_to<T>;
};
return result;
}其中最后一条为复合要求:
大括号里用于判断是否是有效的表达式,右箭头后面判断表达式的值是否符合某些条件
当T为int时,要求都可以成立,表达式的值为true
当T为string时,a++是无效的,表达式的值为false
例2:
1
2
3
4
5
6
7
8
template<typename T>
constexpr bool isIteratable(){
bool result =
requires{
typename T::iterator;
};
return result;
}这个例子中,还有一种要求为条件要求:
格式为typename 表达式,判断类型是否有效
当T为int时,int内没有迭代器,表达式的值为false
当T为string时,string内嵌了迭代器,表达式的值为true
嵌套要求
语法:require 约束表达式
1
2
3
4
5
6
7
8
template<typename T>
constexpr bool isFloat(){
bool result =
requires{
requires std::is_floating_point_v<T>;
};
return result;
}此处约束表达式用于判断是否是浮点数
requires子句
语法:requires 常量表达式(约束)
1
2
3
4
5
template<typename T>
requires std::is_integral<T>::value
bool is_even(T i){
return i%2==0;
}该函数模板设定了一个requires子句,判断传参是否为整型,只有满足该子句函数模板才能实例化,否则编译会报错
requires子句中的表达式也可以使用requires表达式
requires子句中也可以使用&&与||,前者需要满足所有约束,后者需要至少满足一项约束
concept
以上例子中的约束条件即为匿名概念,我们可以将约束条件定义为一个概念
1
2
template<模板参数列表>
concept ConcentName = 约束表达式;定义后我们可以直接使用概念
1
2
3
4
5
template<typename T>
requires std::integral<T>
bool is_odd(T i){
return i%2!=0;
}这里requires子句中使用了预定义的概念integral,定义如下:
1
2
template<typename _Tp>
concept integral = is_integral_v<_Tp>;或将模板中typename替换为概念
或使用概念+auto来定义形参
1
2
3
bool is_odd(std::integral auto i){
return i%2!=0;
}通常定义概念时,概念应该有明确语义
<concept>头文件中也提供了许多预定义概念,大部分类型特征都有对应概念定义