简要概述:我相信这是一个gcc模板部分排序规则中的bug,而且clang是正确的。我已经提交了
bug 66914,虽然它可能是
bug 53499的重复,但我之后没有注意到这一点。
在这个调用中:
a << B::s;
我们有两位合适的候选人:
template <typename T> A<int>::operator<<(const T& );
template <typename N> operator<<(A<N>&, const B& );
您可以重写成员函数,将实例的引用作为第一个参数,并编写两个实例。因此我们有:
template <> operator<<(A<int>&, const B& ); // [T = B]
template <> operator<<(A<int>&, const B& ); // [N = int]
由于两者都是可行的候选项,让我们按照[over.match.best]中的规则来确定哪个是最佳的可行候选项:
根据这些定义,如果对于所有的参数 i,ICSi(F1) 不比 ICSi(F2)更差,则定义一个 viable function F1 比另一个 viable function F2 更好,然后
- 对于某些参数 j,ICSj(F1) 是优于 ICSj(F2) 的 conversion sequence,或者,如果不是这样,
没有,它们都采用相同的参数,因此转换序列是相同的。
- 上下文是由用户定义的转换初始化[...]
不是,与此无关。
- 上下文是通过 conversion function 进行 initialization [...]
不是,与此无关。
- F1 不是函数模板特化而 F2 是函数模板特化,或者,如果不是这样,
不是,它们都是函数模板特化。
- F1 和 F2 都是函数模板特化程序,且 F1 的函数模板比 14.5.6.2 中描述的 partial ordering rules 中的 F2 更加特化。
这是规则中最复杂的部分。最终,两者都不比另一个更加特化。为什么?成员函数实际上是:
template <typename T> A<int>& operator<<(A<int>&, const T& );
如果我们为
T
合成一种类型(称之为
Unique1
),则对于自由函数,推断将失败(因为
Unique1
不匹配
B
)。另一方面,如果我们为
N
合成一种类型(称之为
Unique2
),则对于成员函数,推断将失败(因为
Unique2
不匹配
int
)。
由于两个函数都没有更加特化,我们已经用完了所有的弹药点。函数调用应该是模棱两可的,这是一个gcc的bug。
template<>
。 - n. m.