我在C++中发现了一些我认为奇怪的行为:私有基类中的类型转换运算符在试图解决隐式转换时会混淆编译器:
#include <iostream>
struct Base
{
#ifdef ENABLE
operator bool () const { return true; }
#endif
};
struct Derived : private Base
{
operator int () const { return 7; }
};
int main()
{
Derived o;
std::cout << o << 'n';
return 0;
}
如果没有-DENABLE
,代码编译得很好,并输出7
。有了-DENABLE
,代码就不再编译了,抱怨有一个不明确的重载。我尝试了gcc-4.6.5
、gcc-4.8.1
和clang-3.3
。令人困惑的是,我显然不能要求(bool)o
,因为Base
是私有基础。
这是预期的行为吗?
访问控制总是排在最后。标准报价:
10.2成员名称查找[class.Member.lookup]
1成员名称查找确定名称(id表达式)的含义在类范围内(3.3.7)。名称查找可能导致歧义,在在这种情况下程序是不正确的。对于id表达式,name查找从this的类范围开始;对于限定的id,name查找从nestedname-说明符的作用域开始名称查找发生在访问控制之前(3.4,第11条)。
8如果明确地找到了重载函数的名称,过载解决(13.3)也发生在访问控制之前歧义通常可以通过用类限定名称来解决名称
考虑这两个运算符的原因是:a)基类转换不会被派生类隐藏(如果两者都转换为同一类型,则会隐藏),b)bool
和int
都可以写入stdout,c)两者都不是更好的匹配,因此重载解析会产生歧义。这甚至在访问控制发挥作用之前就产生了一个硬错误。