用户定义的隐式转换运算符和重载决策

时间:2013-04-18 16:41:18

标签: c++

今天,我遇到了一个用户定义的隐式转换运算符的有趣行为。

我们来看看这段代码:

struct Widget {
    Widget(uint64_t) {

    }

    Widget(const std::string &) {

    }

    operator uint64_t() {
        return static_cast<uint64_t>(123456789UL);
    }

    operator std::string() {
        return std::string("Hello");
    }
};

一个基本结构,可以隐式转换为uint64_t或std :: string。

现在,尝试通过std :: cout:

打印出一个Widget实例
#include <iostream>

int main() {
    using std::cout;
    Widget w(123456);

    cout << w;
}

无论出于何种原因,Widget将始终转换为uint64_t。起初我希望调用是模糊的,并且可以通过标准的显式转换来编译:

int main() {
    using std::cout;
    Widget w(123456);

    cout << static_cast<uint64_t>(w);

}

但由于我现在无视的原因,选择了运营商uint64_t。我试着看看C ++规范,但找不到任何有用的东西来回答我的问题。

任何人都可以帮我弄清楚编译器在重载决策方面做了什么吗?

2 个答案:

答案 0 :(得分:3)

uint64_t转换是首选。原因很简单,<<被重载为strings(basic_strings)的模板。编译器总是更喜欢在重载分辨率上完全匹配模板。

答案 1 :(得分:3)

当然,您可以在C ++规范中找到它。

§13.3.1/2§13.3.1/3

中阅读重载决议
  

重载分辨率选择七个不同的调用函数   语言中的语境...

  
      
  • 首先,候选函数的子集(具有适当数量的参数并满足某些其他条件的那些)是   选择形成一组可行的功能(13.3.2)。
  •   
  • 然后根据将每个参数与之匹配所需的隐式转换序列(13.3.3.1)来选择最佳可行函数   每个可行功能的相应参数。
  •   

简而言之,编译器首先列出要使用的候选者,然后尝试找到最适合和更有效的重载。