隐式类型转换优先级是如何确定的



代码如下:

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;
}

我在vs2013中运行代码,输出值是10,如果我注释掉operator int() const{ return val; },输出值将变成a

我的问题是编译器如何确定选择哪种隐式类型转换,我的意思是,因为intchar都是<<操作符的可能选项?

是的,这是模棱两可的,但是模棱两可的原因实际上是相当令人惊讶的。这并不是说编译器不能区分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;
}

问题是along的转换可以通过a.operator char()a.operator int(),两者后面都有一个由整数转换组成的标准转换序列。该标准规定(§13.3.3.1)。[c]/p10,脚注省略):

如果存在多个不同的转换序列,每个转换形参类型的实参,隐式转换序列与参数关联的定义是惟一的转换序列指定了歧义转换序列。为对隐式转换序列进行排序的目的13.3.3.2,二义性转换序列被视为用户定义的序列,与其他序列无法区分用户定义的转换序列。<一口> *

由于aint的转换也涉及到一个用户定义的转换序列,因此它与along的模糊转换序列无法区分,并且在此上下文中没有§13.3.3 [over.match]中的其他规则。Best]也适用于区分两种重载。因此,调用是二义性的,程序是病态的。


*标准中的下一句是"如果一个使用模糊转换序列的函数被选为最佳可行函数,则调用将是病态的,因为调用中的一个参数的转换是模糊的",这似乎不一定正确,但对这个问题的详细讨论可能在单独的问题中更好。

不应该编译,因为转换是不明确的;在我的编译器现场演示中它不会。我不知道为什么你的编译器接受它,或者它如何选择使用哪个转换,但这是错误的。

可以使用显式强制转换来解决歧义:

cout << static_cast<char>(a); // uses operator char()
cout << static_cast<int>(a);  // uses operator int()

就我个人而言,如果我希望它可以转换为多种类型,我可能会使用命名转换函数,而不是操作符。

调试会话给出了结果。一个是全局定义的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++

我不是一个语言律师,但我相信编译器优先考虑成员函数