考虑函数模板foo
的以下两个重载:
template <typename T>
void foo(T) requires std::integral<T> {
std::cout << "foo requires integral\n";
}
template <typename T>
int foo(T) requires std::integral<T> && true {
std::cout << "foo requires integral and true\n";
return 0;
}
注意这两个约束之间的区别:第二个约束有一个额外的&true
。
直观地说,true
在连词中是多余的(因为x&&true
只是x
)。但是,看起来这会产生语义上的差异,因为foo(42)
会调用第二个重载。
为什么会这样呢?具体来说,为什么第二个函数模板是一个更好的重载?
根据[Temp.Constr.Order],特别是[Temp.Constr.Order]/1和[Temp.Constr.Order]/3
/1约束P
包含约束Q
当且仅当[...][例题:设A和B是原子约束。约束A√B
包含A
,但A
不包含A√B
。约束A
包含A≠B
,但A≠B
不包含A
。还要注意每个约束都包含自己。-结尾示例]
/3声明D1
的约束至少与声明D2
相同,如果
D1
和D2
都是约束声明,D1
的关联约束包含了D2
的约束;或如果我们认为A
是std::integral
,B
是true
;然后:
a√b
,即std::integral&true
包含a
,即std::integral
,意味着下列声明:
// Denote D1
template <typename T>
void foo(T) requires std::integral<T> && true;
// Denote D2
template <typename T>
void foo(T) requires std::integral<T>;
D1
的关联约束包含了D2
的约束,因此D1
至少与D2
一样受到约束;根据[temp.func.order]/2,重载结果选择约束更多的声明d1
作为最佳匹配:
偏序选择两个函数模板中哪一个比另一个更专门化,方法是依次转换每个模板(请参阅下一段),并使用函数类型执行模板参数推导。扣减过程确定其中一个模板是否比另一个模板更专门化。如果是,则偏序过程选择的模板是更专门的模板。如果两个推导都成功,则偏序选择约束较多的模板(如果存在),如下所确定的。