为什么GCC不能消除多个继承函数的歧义(但是clang可以)?

时间:2011-11-10 17:14:05

标签: c++ operator-overloading multiple-inheritance overloading ambiguous

  

可能重复:
  Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions?

无法使用g ++ 4.6.1在指定位置编译:

enum Ea { Ea0 };
enum Eb { Eb0 };

struct Sa { void operator()(Ea) {} };
struct Sb { void operator()(Eb) {} };
struct Sbroken : Sa, Sb {};

struct Sworks {
    void operator()(Ea) {}
    void operator()(Eb) {}
};

int main() {
    Sworks()(Ea0);
    Sbroken()(Ea0); // g++ can't disambiguate Ea vs. Eb
}

Clang 2.8确实编译了这段代码,这让我不确定代码是否真的有效C ++。我乐观地总结说clang是对的,g ++是错的,但后来我做了一个小小的改动,让clang有类似的错误:

enum Ea { Ea0 };
enum Eb { Eb0 };

struct Sa { void f(Ea) {} };
struct Sb { void f(Eb) {} };
struct Sbroken : Sa, Sb {};

struct Sworks {
    void f(Ea) {}
    void f(Eb) {}
};

int main() {
    Sworks().f(Ea0);
    Sbroken().f(Ea0); // both clang and g++ say this is ambiguous
}

我在那里做的唯一改变是使用命名函数f而不是operator()。我不明白为什么这应该重要,但确实如此:这个版本不用g ++和clang编译。

2 个答案:

答案 0 :(得分:5)

我认为它与隐藏基类中的函数有关,即使你使用struct而不是{{1},GCC的错误信息也似乎没什么帮助。 }:实际上,错误消息具有误导性,因为现在enumEa是两个不同的类,无隐式转换Eb到{{1不应该出现歧义,但GCC似乎不同意我:http://ideone.com/cvzLW(也参见修改)。

无论如何,如果你把这些函数带到了类范围,那么显式地Ea写成:

Eb

然后它起作用:http://ideone.com/LBZgC

与其他例子相同:

using

代码:http://ideone.com/3hojd

答案 1 :(得分:4)

试图理解标准(第10.2节)中的实际文本并不容易, 但是有一个例子可以说清楚:名称x的名称查找 如果派生类中不存在名称,则派生类中的类失败 class,但它存在于多个基类中,而不是 隐。 (隐藏在这里不相关,因为它只在虚拟时进行干预 继承存在。)据我所知,情况就是这样 无论会员的名字如何;我发现如果没有例外 成员恰好有特殊名称operator()。超载 决议没有发挥作用,因为他们的名字是失败的 查找,在完全构建过载集之前。我相当确定 这两段代码都是非法的,而且还有一个bug 铛。

您可以使用using声明将名称注入派生名称 class,或者您可以在派生中明确定义转发运算符 类。一旦在派生类中找到名称,编译器就会停止, 并且不会查看基类。