今天,我遇到了一个用户定义的隐式转换运算符的有趣行为。
我们来看看这段代码:
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 ++规范,但找不到任何有用的东西来回答我的问题。
任何人都可以帮我弄清楚编译器在重载决策方面做了什么吗?
答案 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)来选择最佳可行函数 每个可行功能的相应参数。
简而言之,编译器首先列出要使用的候选者,然后尝试找到最适合和更有效的重载。