考虑以下课程:
class Foo
{
public:
void operator [] (const std::string& s) { }
void operator [] (std::size_t idx) { }
};
Run Code Online (Sandbox Code Playgroud)
这里,给定一个实例Foo f,表达式f[0]不含糊,因为编译器选择第二个重载.同样,表达式f["abc"]不含糊,因为编译器选择第一个重载(因为a const char*可以转换为a std::string).
那么,为什么呢,如果我们有两个Base类,每个都有不同的重载,那么突然有歧义?
假设我们有:
class Base1
{
public:
void operator [] (const std::string& s) { }
};
class Base2
{
public:
void operator [] (std::size_t idx) { }
};
class Derived : public Base1, public Base2
{ };
Run Code Online (Sandbox Code Playgroud)
现在,如果我们说:
Derived d;
d[0];
Run Code Online (Sandbox Code Playgroud)
编译器抱怨:
error: request for member ‘operator[]’ is ambiguous
d[0];
^
note: candidates are: void Base2::operator[](std::size_t)
void operator [] (std::size_t idx) { }
^
note: void Base1::operator[](const string&)
void operator [] (const std::string& s) { }
Run Code Online (Sandbox Code Playgroud)
为什么两个运算符重载现在都在Base类中会导致任何歧义?有没有办法解决这个问题?
编辑:这可能是编译器错误(我正在使用GCC 4.8.1)
这不是重载解析的问题,而是成员名称查找,它在10.2中定义.考虑(因为我不想operator[]到处写):
struct base1 { void f(int); };
struct base2 { void f(double); };
struct derived : base1, base2 {};
int main() {
derived d; d.f(0);
}
Run Code Online (Sandbox Code Playgroud)
当f在后缀表达式中查找开始时d.f(0),它将首先查看derived并找到f根本不解析的任何内容.10.2/5然后要求查找并行进行到所有基类,构建单独的查找集.在这种情况下,S(f,base1)= {base1 :: f} 和S(f,base2)= {base2 :: f}.然后按照10.2/6中的规则合并这些集合.当其中一个集合为空或者不同集合的查找以相同成员结束时(考虑到它达到共同基础),第一个子弹处理合并.第二个子弹是有趣的,因为它适用于此
10.2/6子弹2
否则,如果声明组S的(F,BI)和S(F,C)不同,合并是模棱两可:新S(F,C)与一个无效的声明集和子对象的工会设置查找集.在后续合并中,无效的声明集被认为与其他任何不同.
也就是说,S(f,base1)与S(f,base2)不同,因此S(f,导出)成为无效的声明集.查找失败.
| 归档时间: |
|
| 查看次数: |
519 次 |
| 最近记录: |