此答案基于对标准段落的抽象语法树的错误解析。“回到标准”部分中假设的条件分组结果不是预期的。预期的分组是 Johannes Schaub 在他的回答中显示的分组。
当我们没有一个至少比相应的 T 专业化时,为什么会有提到的后备?
我同意你的观点,第二部分(实际上是整个第二个条件)是多余的。
一些参考词汇:
让我们玩一些逻辑的乐趣,并为一对对应的参数介绍两个模板之间的 3 个基本关系:
- 比: 对于参数
Ti
和Ui
分别更专业,一个模板匹配另一个模板,反之则不然。我将其表示为Ti < Ui
;
- 同样专业化:对于参数
Ti
和Ui
分别,一个模板匹配另一个模板,反之亦然。我将其表示为Ti == Ui
;
- Specialization-incomparable:对于参数
Ti
和,对于特定参数Ui
,没有一个模板与另一个模板匹配。我将其表示为T1 ~ U1
。
例如,在下面的代码片段中:
template<typename X> struct A { };
template<typename X> struct B { };
template<typename X> void foo(A<X>, X, A<X>) { } // 1
template<typename X> void foo(X, X, B<X>) { } // 2
对于第一个参数,(1) 比 ( <
) (2) 更专业;对于第二个参数, (1) 与 (或 "与", ==
) (2) 一样特化;对于第三个参数,(1) 与 ( ~
) (2) 是特化不可比的。
现在让我们定义一个派生关系:
- 对于各个参数,模板(1)至少与另一个模板(2)一样特化
Ti
,并且Ui
当(Ti < Ui)
或时(Ti == Ui)
,即当(1) 比(2) 更特化时,或者(1) 与(2) 一样特化。因此,在上面的示例中,T1 <= U1
、T2 <= U2
和U2 <= T2
。
回到标准:
在几个括号的帮助下,上面的引用变为 (A && (B1 || B2)):
[...] 对于正在考虑的每种类型:
(一个给定的模板至少对所有类型都是专门化的,并且对某些类型更加专门化)
AND
(另一个模板不是更专业于任何类型
OR
至少不适合任何类型)
T1, ..., Tn
给定两个要根据参数类型和的相应序列排序的模板U1, ..., Un
,条件 (A):
[...] 一个给定的模板至少对所有类型都是专用的,并且对某些类型集更专业 [...]
意味着对于每个i = 1..n
,Ti <= Ui
和某些j
s in 1..n
,它应用更严格的条件Tj < Uj
. 删除 index i
,这意味着对于每个参数:
(T < U) || (T == U) // (A)
该条件与另一个条件 (B) 进行逻辑合取 (“and”),而后者又是两个子条件 (B1) 和 (B2) 的逻辑合取 (“or”)。让我们开始检查子条件(B1):
[...] 另一个模板不是更专业于任何类型 [...]
这意味着对于 any i
,永远不会是 that Ui < Ti
,这意味着:
Ti
比Ui
( Ti < Ui
) 更专业;或者
Ti
并且Ui
同样专业化(Ui == Ti
);或者
Ti
并且Ui
是专业化不可比的 ( Ui ~ Ti
):
更正式地说:
!(U < T) <==> (T < U) || (T == U) || (T ~ U) // (B1)
现在让我们看看第二个子条件 (B2),它与 (B1) 进行逻辑分离:
[...] 至少不适合任何类型 [...]
这是 的否定U <= T
,这意味着:
!(U <= T) <==> !((U == T) || (U < T)) ==> !(U == T) && !(U < T)
换句话说,T
andU
不是同等专业的,也不U
是比 更专业的T
。因此,剩下的唯一可能是:
(T < U) || (T ~ U) // (B2)
现在很明显,(B2) 蕴含 (B1),因为 (B2) 更具限制性。因此,它们的析取 (B) 将与 (B1) 重合,并且 (B2) 是多余的:
(T < U) || (T ~ U) || (T == U) // (B)
但是这里同样明显的是(A)比(B)更严格,所以(A)和(B)的合取等价于(A)。
结论:
整个条件(B)是多余的。