以下是代码:
class A{
public:
int val;
char cval;
A():val(10),cval('a'){ }
operator char() const{ return cval; }
operator int() const{ return val; }
};
int main()
{
A a;
cout << a;
}
我在VS 2013中运行代码,输出值为10
,如果我注释掉operator int() const{ return val; }
,则输出值将变为a
。
我的问题是编译器如何确定选择哪种隐式类型转换,我的意思是因为int
和char
都是<<
运算符的可能选项?
答案 0 :(得分:5)
是的,这是模棱两可的,但模棱两可的原因实际上相当令人惊讶。并不是编译器无法区分ostream::operator<<(int)
和operator<<(ostream &, char)
;后者实际上是一个模板,而前者不是,所以如果匹配同样好,第一个将被选中,并且这两个之间没有歧义。相反,歧义来自ostream
的其他成员operator<<
重载。
struct A{
operator char() const{ return 'a'; }
operator int() const{ return 10; }
};
struct B {
void operator<< (int) { }
void operator<< (long) { }
};
int main()
{
A a;
B b;
b << a;
}
问题在于,a
到long
的转换可以通过a.operator char()
或a.operator int()
进行转换,然后是标准转换序列,其中包含整数转换。标准说(§13.3.3.1[over.best.ics] / p10,脚注省略):
如果存在多个不同的转换序列,则每个转换都会转换 参数类型的参数,隐式转换序列 与参数相关联的定义为唯一转换 序列指定模糊转换序列。为了 如上所述对隐式转换序列进行排序的目的 13.3.3.2,模糊转换序列被视为用户定义的序列,与任何其他序列无法区分 用户定义的转换序列。 *
由于a
到int
的转换也涉及用户定义的转换序列,因此与a
到{{em>模糊转换序列无法区分{1}},在此上下文中,§13.3.3[over.match.best]中的其他规则也不适用于区分两个重载。因此,电话是模糊的,程序是不正确的。
* 标准中的下一句话说“如果选择使用模糊转换序列的函数作为最佳可行函数,则调用将是格式错误,因为转换为调用中的一个参数是模棱两可的。“,这似乎不一定正确,但在separate question中对此问题的详细讨论可能更好。 子>
答案 1 :(得分:4)
它不应该编译,因为转换是模糊的;它与我的编译器没有关系:live demo。我不知道为什么你的编译器会接受它,或者它如何选择使用哪种转换,但这是错误的。
您可以使用明确的演员来解决歧义:
cout << static_cast<char>(a); // uses operator char()
cout << static_cast<int>(a); // uses operator int()
就个人而言,如果我希望它可以转换为多种类型,我可能会使用命名转换函数而不是运算符。
答案 2 :(得分:1)
调试会话给出了结果。一个是全局定义的operator<<
,另一个是类方法。你猜哪个人在调用哪个。
Test.exe!std::operator<<<std::char_traits<char> >(std::basic_ostream<char,std::char_traits<char> > & _Ostr, char _Ch)
msvcp120d.dll!std::basic_ostream<char,std::char_traits<char> >::operator<<(int _Val) Line 292 C++
我不是语言律师,但我相信编译器首先优先考虑成员函数。