约束和要求详解
要指定模板参数的需求,您需要约束,这些约束是布尔表达式,在编译时计算为true或false,以决定是否实例化和编译模板。
约束可以是:
- 一个临时布尔编译时表达式(语法受限,因此可能需要括号以避免歧义)
- 需要指定所需操作和类型的表达式
- 一个概念(之前定义,通过使用关键字概念)
约束的基本应用是require子句,它使用关键字require和约束来限制模板的可用性。所有约束也可以用于任何可以使用布尔表达式的地方(特别是作为if constexpr条件)。
要组合多个约束,可以使用&&。例如:
template<typename T>
requires (sizeof(T)>4) //ud-hoc Boolean expression
&& requires { typename T::value_type;} //requires expression
&& std::input_iterator<T> //concept
约束的顺序并不重要。也可以使用||表示替代约束:
template<typename T>
requires std::integral<T> || std::floating_point<T> T power(T b,Tp);
很少需要指定替代约束,也不应该太随意,因为在require子句中过度使用||操作符可能会占用编译资源(即,使编译明显变慢)。
单个约束也可以涉及多个模板参数:例如
template<typename T, typename U>
requires std::convertible_to<T, U> auto f(T x,U y){
...
}
这样,约束可以在类型参数之间施加关系。
特殊布尔表达式
为模板制定约束的第一种方法是使用转换为true或false的编译时表达式。
- 类型谓词,例如类型特征
- 编译时变量(用constexpr或constinit const定义)
- 编译时函数(使用 constexpr 或 consteval 定义)
让我们看一些限制模板可用性的特殊布尔表达式的例子
-
仅当int和long的大小不同时可用
template<typename T> requires (sizeof(int) != sizeof(long)) -
仅当sizeof (T)不太大时可用
template<typename T> requires (sizeof(T)<=64) ... -
仅当非类型模板参数Sz大于零时可用
template<typename T, std::size_t Sz> requires (Sz > 0) ..· -
仅适用于原始指针和 nullptr:
template<typename T> requires (std::is_pointer_v<T> || std::same_as<T, std::nu111ptr_t>) ... std::same_as is a new standard concept. You could also use the type trait std::is_same<>: template<typename T> requires (std::is_pointer_v<T> || std::is_same_v<T, std::nullptr_t>) ... -
仅当参数不能作为字符串使用时可用
template<typename T> requires (!std::convertible_to<T, std::string>) std::convertible_to is a new standard concept.你也可以使用类型:
trait std::is_convertible<>: template<typename T> requires (!std::is_convertible_v<T, std::string>) ... -
仅当实参是指向整型值的指针(或类指针对象)时可用
template<typename T> requires std::integral<std: :remove_reference_t<decltype(*std::declval<T>())>>注意,操作符
*通常产生一个引用,而不是整型。因此,我们采取以下措施-假设我们有一个类型为T的对象:std::declval()
- 为它调用运算符*:*
- 询问它的类型:decltype()
- 删除引用:std::remove_reference_v<>
- 检查整型:std::integral
std:: integral是一个新的标准概念。你也可以使用类型
trait std::is integral<>。这个约束也可以通过std::optional<int>来满足。 -
只有当非类型模板参数Min和Max的最大公约数大于1时才可用
template<typename T> constexpr bool gcd(T a,T b); // 最大公约数 template<typename T, int Min, int Max> requires (gcd(Min,Max)> 1) // 如果 u GCD 大于 1 ... -
禁用模板(临时)
template<typename T> requires false
通常,整个表达式需要用括号括起来。
唯一的例外是使用标识符、::和<…>(可选与&&和II组合)
requires std::convertible_to<T,int>
&&
(!std: :convertible_to<int,T>)
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情”