【发布时间】:2012-02-13 11:00:36
【问题描述】:
这个例子似乎可以用 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])(在用户定义的转换和标准转换 double 到 long 之后)。
如果我将d["32"] 写成d.operator[]("32"),那么重载决议甚至不会考虑选项2,并且clang 也可以正常编译。
编辑:(澄清问题)
这似乎是重载解决方案中的一个复杂领域,因此,我非常感谢在这种情况下详细解释重载解决方案并引用标准的答案(如果有一些晦涩/先进的可能是未知规则)。
如果 clang 是正确的,我也很想知道为什么这两者模棱两可/一个不优于另一个。答案可能必须解释重载解决方案如何考虑两个候选对象所涉及的隐式转换(用户定义和标准转换),以及为什么一个不比另一个更好。
注意:如果将 operator double() 改为 operator bool(),这三个 (clang, vc, gcc) 都会拒绝编译,并出现类似的模棱两可的错误。
【问题讨论】:
-
澄清(可能的)歧义来自何处:
a[b]等价于b[a],当operator[]未重载时。 -
对,我正准备在几分钟前添加。会的,谢谢。
-
既然你提到你的 GCC 很旧,我在尚未发布的 4.7 上进行了尝试。它的作用和你的一样:编译原件就好了,用
operator bool出错。 -
感谢您试用。将进行编辑以反映您的努力。
-
@MikeSeymour:
a[b]在这种情况下不等于b[a](因为在这种情况下a不是const char*或可转换为它)。你说的是这种情况:char a[100]; int b;然后a[b]相当于b[a]。
标签: c++ visual-c++ clang implicit-conversion overload-resolution