2

The following code

struct Foo{};
struct Bar{};

struct Base {
    Foo func1(const Foo , const Bar = Bar{}) const {
        return {};
    };
};

struct Derived : public Base {
    using Base::func1;
    Foo func1(const Foo ) const {
        return {};
    };
};

int main() {
    Foo foo;
    Derived der;
    der.func1(foo);
}

is rejected by ICX and clang, but accepted by GCC (up to 13.1). https://godbolt.org/z/4M3rrs3r4

I think GCC is wrong here. If the two func1s were non-members, GCC would reject the call as ambiguous.

Am I right?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Bulletmagnet
  • 5,665
  • 2
  • 26
  • 56
  • 1
    looks like a gcc bug to me. the derived function is allowed to hide the base one, but only if: *the derived class already has a member with the same name, parameter list, and qualifications* ([source](https://en.cppreference.com/w/cpp/language/using_declaration)) – NathanOliver Jun 20 '23 at 17:59
  • I see it the other way. Because `Base::func1` and `Derived::func1` have different parameter list, there's no hiding but just overriding. `der.func1(foo)` matches the signature of `Derived::func1` better than `Base::func1`. This match is better than using the (default) second parameter of `Base::func1`. So, there's no ambiguous call and GCC is right. – Ripi2 Jun 20 '23 at 18:18
  • @Ripi2 They are both viable and match exactly (defaulted parameters are not considered during overload resolution). If you replace the using-declaration with an overload it also fails to compile on GCC: https://godbolt.org/z/EYfasr7G5 – Artyer Jun 20 '23 at 18:22
  • @Artyer THX. Then it's about how GCC considers the "using-declaration", forgetting overload resolution. – Ripi2 Jun 20 '23 at 18:25
  • @Ripi2 Right, they don't match so the base function is included, which it should be. The issue with that is both can be called with `der.func1(foo);` since the second parameter of the base function is defaulted. Clang gets that right, GCC doesn't – NathanOliver Jun 20 '23 at 18:25

2 Answers2

1

It is a bug of the compiler gcc.

From the C++ 20 (9.9 The using declaration)

15 [Note 6 : For the purpose of forming a set of candidates during overload resolution, the functions that are introduced by a using-declaration into a derived class are treated as though they were members of the derived class (11.8). In particular, the implicit object parameter is treated as if it were a reference to the derived class rather than to the base class (12.4.2). This has no effect on the type of the function, and in all other respects the function remains a member of the base class. — end note]

and (9.3.4.7 Default arguments)

  1. ... When a declaration of a function is introduced by way of a using-declaration (9.9), any default argument information associated with the declaration is made known as well.

So for the overload resolution the set of function candidates in the class Derived consists of two functions

Foo func1(const Foo , const Bar = Bar{}) const {
    return {};
}

and

Foo func1(const Foo ) const {
    return {};
}

And such a call

der.func1(foo);

in this case is ambiguous. Either function can be called.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

It is a bug that was introduced with GCC 7: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82894