7

In C++ one cannot overload in one class a member function with ref-qualifier with a member function without ref-qualifier. But at the same time it is possible to inherit one member function from a parent class and overload it in a child class as in the example:

struct A {
    void f() {}
    //void f() & {} //overload error everywhere
};

struct B : A {
    using A::f;
    void f() & {} //ok everywhere
};

int main() {
    B b;
    b.f(); //ok in GCC only
}

Only during the invocation of f, Clang complains that call to member function 'f' is ambiguous. But GCC accepts the program without any error, demo: https://gcc.godbolt.org/z/5zzbWcs97

Which compiler is right here?

Fedor
  • 17,146
  • 13
  • 40
  • 131

1 Answers1

6

GCC is correct to accept this, but the situation changed recently. The current phrasing is that a using-declaration in a class ignores (base-class) declarations that would be ambiguous (in a sense that is more strict than for overload resolution, partly because there is no argument list yet) with other declarations in the class. void() and void() & members are ambiguous in this sense, so b.f finds only B’s f and the call is valid.

In previous (as of this writing, that means “published”) versions of the standard, both functions would be made available because the & distinguished them (in a sense that is even stricter), which would not only render the call ambiguous (as Clang says) but be ill-formed outright because the base- and derived-class functions were checked for overload compatibility which they lack.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • Thanks. Could you please add a link to this point in the standard? – Fedor Nov 19 '21 at 07:21
  • 2
    @Fedor http://eel.is/c++draft/namespace.udecl#11 – Language Lawyer Nov 19 '21 at 09:44
  • So, which compiler is actually wrong here in the end? I'd like to report this bug to one of them, so that they act the same – dragonroot Jun 06 '22 at 05:55
  • @dragonroot: GCC is correct. The committee doesn’t usually issue the Technical Corrigenda needed to formally make this true for C++20, but I’d expect it to be (eventually) implemented for all language modes back to C++11. Clang isn’t right in any language version because it rejects only the call. – Davis Herring Jun 06 '22 at 20:42
  • Thanks, reported here: https://github.com/llvm/llvm-project/issues/55907 – dragonroot Jun 06 '22 at 22:57