这个例子似乎可以用 VC10 和 gcc 编译(虽然我的 gcc 版本很旧)。
编辑:R. Martinho Fernandez 在 gcc 4.7 上尝试了这个,行为仍然相同。
struct Base
{
operator double() const { return 0.0; }
};
struct foo
{
foo(const char* c) {}
};
struct Something : public Base
{
void operator[](const foo& f) {}
};
int main()
{
Something d;
d["32"];
return 0;
}
但是clang抱怨:
test4.cpp:19:6: error: use of overloaded operator '[]' is ambiguous (with operand types 'Something' and 'const char [3]')
d["32"]
~^~~~~
test4.cpp:13:10: note: candidate function
void operator[](const foo& f) {}
^
test4.cpp:19:6: note: built-in candidate operator[](long, const char *)
d["32"]
^
test4.cpp:19:6: note: built-in candidate operator[](long, const restrict char *)
test4.cpp:19:6: note: built-in candidate operator[](long, const volatile char *)
test4.cpp:19:6: note: built-in candidate operator[](long, const volatile restrict char *)
通过查看此表达式,重载决策正在考虑两个可能的函数:
- 调用 Something::operator[] (在用户定义的转换之后)
- 为 const char* 调用内置运算符(想想“32”[d])(在用户定义的转换和标准转换双倍到长之后)。
如果我写d["32"]
为 as d.operator[]("32")
,那么重载决议甚至不会查看选项 2,并且 clang 也将编译得很好。
编辑:(澄清问题)
这似乎是重载解决方案中的一个复杂领域,因此我非常感谢在这种情况下详细解释重载解决方案并引用标准的答案(如果有一些模糊/高级可能是未知的规则) .
如果clang是正确的,我也有兴趣知道为什么这两者模棱两可/一个不优于另一个。答案可能必须解释重载决议如何考虑两个候选者所涉及的隐式转换(用户定义和标准转换)以及为什么一个不比另一个更好。
注意:如果将 operator double() 更改为 operator bool(),所有三个 (clang, vc, gcc) 将拒绝编译,并出现类似的模棱两可的错误。