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

时间:2014-08-19 14:03:01

标签: c++ implicit-conversion

以下是代码:

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

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

3 个答案:

答案 0 :(得分:5)

是的,这是模棱两可的,但模棱两可的原因实际上相当令人惊讶。并不是编译器无法区分ostream::operator<<(int)operator<<(ostream &, char);后者实际上是一个模板,而前者不是,所以如果匹配同样好,第一个将被选中,并且这两个之间没有歧义。相反,歧义来自ostream的其他成员operator<<重载。

minimized repro

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[over.best.ics] / p10,脚注省略):

  

如果存在多个不同的转换序列,则每个转换都会转换   参数类型的参数,隐式转换序列   与参数相关联的定义为唯一转换   序列指定模糊转换序列。为了   如上所述对隐式转换序列进行排序的目的   13.3.3.2,模糊转换序列被视为用户定义的序列,与任何其他序列无法区分   用户定义的转换序列。 *

由于aint的转换也涉及用户定义的转换序列,因此与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++

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