#include <iostream>
template< typename U >
struct base {
template< typename T >
base const & operator<<( T x ) const {
std::cout << sizeof( x ) << std::flush;
return *this;
}
};
template< typename U >
struct derived : public base< U > {
using base<U>::operator<<;
derived const & operator<<( float const & x ) const {
std::cout << "derived" << std::flush;
return *this;
}
};
int main() {
unsigned char c( 3 );
derived< double > d;
d << c;
d.operator<<( c );
return 0;
}
请您解释所涉及的规则,以获得上述代码的正确答案(与模板相关的重载和覆盖,整体提升......)?有效吗?如果规则太长,请提供文献指南。最新的编译器不同意正确的结果。 gcc-4.6和icpc-12.1.0声明“11”是正确答案,但VS2010由于含糊不清而拒绝编译d << c;
但接受d.operator<<( c );
。后者输出1
iirc。那么谁是对的,谁错了?
答案 0 :(得分:3)
“11”是正确的输出。
对于两个表达式,派生运算符&lt;&lt;和基本运算符&lt;&lt;是候选人。然后基于它们所需的隐式转换序列来比较候选者。因为基本运算符&lt;&lt;是一个模板函数,其中推导出类型T以匹配它出现的参数,在两种情况下都是更好的匹配。
确切的规则很长。您可以在当前C ++草案标准的第13.3节重载决议中找到详细信息,n3337链接到工作组论文的this list。
如果你问为什么MSVC不编译一个语句,我不完全确定,但是当有多个计算的ICS彼此不比时(如13.3中定义的那样),函数调用是不明确的。 3)。在d << c
的情况下,MSVC似乎计算了至少一个重载的错误ICS,但诊断没有提供更多细节:
error C2666: 'derived<U>::operator <<' : 2 overloads have similar conversions
with
[
U=double
]
ConsoleApplication1.cpp(24): could be 'const derived<U> &derived<U>::operator <<(const float &) const'
with
[
U=double
]
ConsoleApplication1.cpp(14): or 'const base<U> &base<U>::operator <<<unsigned char>(T) const'
with
[
U=double,
T=unsigned char
]
while trying to match the argument list '(derived<U>, unsigned char)'
with
[
U=double
]
答案 1 :(得分:0)
它无法编译,因为您要求operator <<
自动调用。这就像拥有operator +
一样,并且拥有可以转换为基本类型的转换运算符(例如,转换为int
)。例如:
class Conversion
{
public:
operator int()
{
return 5;
}
int operator +(int x)
{
return 10;
}
};
使用它像:
Conversion conv;
conv + 1.0;
此处operator +
无法隐式调用,因为operator int
也是可能的。但是,如果您通过int
,则会调用operator +(int)
。要使用double
调用operator +,我们可以这样做:
conv.operator+(1.0);
我不了解编译器规则和严格的标准定义。
我还发现,如果我们将base
和derived
类更改为非模板类,问题仍将存在(在VC10 / 11中):
struct base {
base const & operator<<( int x ) const {
std::cout << sizeof( x ) << std::flush;
return *this;
}
};
struct derived : public base{
using base::operator<<;
derived const & operator<<( float const & x ) const {
std::cout << "derived" << std::flush;
return *this;
}
};
int main()
{
derived d;
d<<10.0; // ERROR
}