重载决议向成员函数添加一个附加参数只是为了重载决议的目的:
[over.match.funcs]/2
候选函数集可以包含要根据同一参数列表解析的成员函数和非成员函数。为了使自变量和参数列表在这个异构集合中具有可比性,成员函数被认为有一个额外的参数,称为隐式对象参数,它表示已调用成员函数的对象。
/4
对于非静态成员函数,隐式对象参数的类型为
—“左值引用cv X
” 对于没有声明的函数引用限定符或与&
引用限定符
—“右值引用cv X
” 对于用&&
引用限定符
where X
是该函数所属的类,并且cv is the cv- 成员函数声明的限定。
遵循一些特殊规则,例如允许将右值绑定到此隐式对象参数(用于调用右值上没有引用限定符的成员函数,例如ostr{std::cout}<<"hello"
).
函数签名包括我们需要比较重载解析的隐式对象参数是:
template<class T>
ostr& ostr::operator<<(ostr&, const T&); // F1
template<class Stream>
Stream& ::operator<<(Stream&, const xy&); // F2
替换后os << x
,我们得到same签名:
ostr& ostr::operator<<(ostr&, const xy&);
ostr& :: operator<<(ostr&, const xy&);
因此,只有 [over.match.best]/1 中的“决胜局”之一可以解决歧义。事实上,可以应用,即“F1
比更专业F2
"(反之亦然):函数模板的部分排序。
注意:指定添加隐式对象参数的过程again在部分排序的描述中[temp.func.order]/3。
对于部分订购F1
and F2
(如上所述),我们首先创建两个独特的类型:
struct unique_T {};
struct unique_Stream {};
然后我们改造F1
into F1'
通过替换模板参数T
具有独特的类型unique_T
(同样对于F2
):
ostr& ostr::operator<<(ostr&, const unique_T&);
ostr& :: operator<<(unique_Stream&, const xy&);
变换函数的参数F1'
现在用于尝试推导未转换的模板参数F2
:
ostr a0;
unique_T a1; // no reference, no cv-qualifier
::operator<<(a0, a1) // does template argument deduction succeed?
// reminder: signature of ::operator<<
template<class Stream>
Stream& ::operator<<(Stream&, const xy&);
扣除成功为a0
[with Stream
= ostr
],因此类型ostr&
from F1
被认为至少与相应的第一个参数的类型一样专业F2
(Stream&
, with Stream
是模板参数)。我不确定第二个参数会发生什么a1
,因为第二个参数没有发生扣除::operator<<
(它的类型是const xy&
).
现在我们用参数重复这个过程F2'
并尝试推导模板参数F1
:
unique_Stream a0;
xy a1;
ostr::operator<<(a0, a1);
// reminder: signature of ostr::operator<<
template<class T>
ostr& ostr::operator<<(ostr&, const T&);
在这里,第一个参数没有发生演绎,但第二个参数发生并成功 [withT
= xy
].
我的结论是,没有哪个函数模板比它更专业了。因此重载解析应该失败由于含糊不清。