3

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

我们来看这段代码:

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。起初,我希望调用是模棱两可的,并且符合标准的显式转换为 compile :

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

    cout << static_cast<uint64_t>(w);

}

但由于我现在忽略的原因,选择了 operator uint64_t。我试图查看 C++ 规范,但找不到任何有用的东西来回答我的问题。

谁能帮我弄清楚编译器对重载解析做了什么?

4

2 回答 2

3

uint64_t转换是首选。原因很简单,它<<被重载为strings(basic_strings) 的模板。在重载决议上,编译器总是更喜欢精确匹配而不是模板。

于 2013-04-18T16:48:46.417 回答
3

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

在和中读取过载解决方案§13.3.1/2§13.3.1/3

重载解析选择函数在语言内的七个不同上下文中调用...

 

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

 

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

于 2013-04-18T16:51:31.500 回答