2

In the following test program, struct B has two member functions f, which can be called using B{}.f(): one ordinary f() and another with explicit object f(this A).

struct A {
    int f() { return 1; }
};

struct B : A {
    using A::f;
    int f(this A) { return 2; }
};

int main() {
    return B{}.f();
}

Which function must be selected by overload resolution?

GCC and MSVC prefer ordinary member function f() and the program returns 1.

But Clang makes the opposite choice, selecting explicit object member function f(this A) and the program returns 2.

Online demo: https://gcc.godbolt.org/z/1bo69Ta8q

Which compiler is correct here if any (why not ambiguity of overload resolution)?

5
  • 1
    "Which compiler is correct here if any (why not ambiguity of overload resolution)?..." GCC and msvc are correct because calling the implicit member function doesn't require a conversion. Commented Jul 22, 2024 at 16:33
  • 1
    "why not ambiguity of overload resolution" - Related: CWG 2789 Commented Jul 22, 2024 at 16:38
  • You can also see this directly by adding a copy ctor for class A and noticing that clang incorrectly uses the copy ctor while gcc and msvc do not. Demo Commented Jul 22, 2024 at 16:50
  • I think it ought to be ambiguous if you had written int f(this B) instead of int f(this A), but it seems only MSVC has the same opinion: gcc.godbolt.org/z/W7Yd4Eved Commented Jul 22, 2024 at 17:05
  • 2
    Here is the clang bug report Commented Jul 22, 2024 at 17:12

1 Answer 1

2

tldr; Clang is wrong in choosing the explicit object member function for the reason(s) explained below. Here is the confirmed clang bug.

Which compiler is correct here if any (why not ambiguity of overload resolution)?

First note that as per over.match.func.general, the function nominated by using A::f is considered to be a member of the derived class for the purposes of defining the type of the implicit object parameter.

This means that for the call B{}.f(), the implicit object member function is a better match because it doesn't require conversion for the argument B{}.

For reference here is over.match.func.general that states:

For non-conversion functions introduced by a using-declaration into a derived class, the function is considered to be a member of the derived class for the purpose of defining the type of the implicit object parameter.


We can also see this by adding a copy ctor for class A and noticing that clang incorrectly uses the copy ctor for the conversion but gcc and msvc do not. Demo

Thus, gcc and msvc are right in choosing the implicit version that was made visible by using A::f;.


Here is the confirmed clang bug:

Clang chooses the incorrect overload when explicit and implicit member functions are involved

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.