c++ 概念和需求的例子
请参考以下函数模板,该模板返回两个最大值:
template<typename T>
T maxValue(T a,Tb)
{ return b<a?a:b; }
对于两个类型相同的参数,可以调用此函数模板,前提是对参数执行的操作(与运算符比较<和复制)有效。但是,传递两个指针将比较它们的地址而不是它们引用的值。
逐步改进模板
为了解决这个问题,我们可以为模板配备一个约束,以便在传递原始指针时它不可用:
template<typename T>
requires (!std::is_pointer_v<T>) T maxValue(T a,T b)
{
return b<a?a:b;}
在这里,约束是在 require 子句中表述的,该子句与关键字 require 一起引入(还有其他方法可以表述约束)。
为了指定模板不能用于原始指针的约束,我们使用标准类型特征 std::is_pointer_v<>(它生成标准类型特征 std::is_pointer<> 的值成员)。
有了这个约束,我们不能再将函数模板用于原始指针:
int x=42; int y=77;
std::cout <<maxValue(x,y)<<'\n';
// OK: int 的最大值
std::cout <<maxValue(&x,&y)<<'\n';
//错误:约束不满足
该需求是编译时检查,对已编译代码的性能没有影响。这仅仅意味着模板不能用于原始指针。当传递原始指针时,编译器的行为就像模板不存在一样。
定义和使用一个概念
我们很可能不止一次地需要一个指针约束。因此,我们可以为它引入一个概念
template<typename T>
concept IsPointer = std::is_pointer_v<T>;
概念是一个模板,我们在其中为传递的模板参数的一个或多个约束引入了一个名称。
在等号之后,我们必须将约束指定为在编译时计算的布尔表达式。
在这种情况下,我们要求传递给 IsPointer 的 temnplate 参数<>必须是原始指针。
现在,我们可以用这个概念来约束 maxValue()模板:
template<typename T>
requires (!IsPointer<T>) T maxValue(T a,T b)
{
return b<a?a:b; }
概念重载
通过使用约束和概念,我们甚至可以重载maxValue()模板,让一个实现用于指针,另一个实现用于其他类型
template<typename T>
requires (!IsPointer<T>)
T maxValue(T a,Tb)
// maxValue() 不用于指针
{
return b<a?a:b; //比较值
}
template<typename T>
requires IsPointer<T>
auto maxValue(T a,T b) //指针的 maxValue ()
{
return maxValue(*a,*b); //比较指针指向的值
}
请注意,只需用概念约束模板的require子句不再需要圆括号。现在,我们有两个同名的函数模板,但每种类型只有一个可用:
int x=42;
int y=77;
std::cout << maxValue(x,y) <<'\n'; //调用 maxValue() 不用于指针
std::cout<<maxValue(&x,&y)<<'\n'; //为指针调用 maxValue()
因为指针的实现将返回值的计算委托给指针所引用的对象,所以第二个调用使用了两个maxValue()模板。
当将指针传递给int时,我们实例化T为int*的指针模板,并实例化T为int时不用于指针的基本maxValue()模板。
这甚至可以递归地工作。我们可以要求指向int型指针的指针的最大值
int* xp=&x;
int* yp=&y;
std::cout <<maxValue(&xp,&yp)<<'\n'; //对于 int * * 使用 callsmaxValue ()
带概念的重载解决方案
重载解析认为有约束的模板比没有约束的模板更特殊。因此,只约束指针的实现就足够了
template<typename T> T maxValue(T a,T b) //maxValue()表示 T 类型的值
{
return b<a?a:b; //比较值
}
template<typename T>
requires IsPointer<T>
auto maxValue(T a,T b) //maxValue()用于指针(更高的优先级)
}
return maxValue(*a,*b); //指针指向的 compure 值
}
但是,要小心:一次使用引用和一次不使用引用的重载可能会导致歧义。通过使用概念,甚至可以选择一些约束而不是其他约束。然而,这要求使用包含其他概念的概念。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情”