C++ Logo

std-proposals

Advanced search

Re: Ambiguous function overload resolution for multiple inheritance

From: Ville Voutilainen <ville.voutilainen_at_[hidden]>
Date: Mon, 23 Sep 2019 22:52:00 +0300
On Mon, 23 Sep 2019 at 22:00, Peter Neiß via Std-Proposals
<std-proposals_at_[hidden]> wrote:
>
> On Mon, 23 Sep 2019 20:26:15 +0200, Christof Meerwald via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
>
> > On Mon, Sep 23, 2019 at 07:16:43PM +0200, Peter Neiß via Std-Proposals
> > wrote:
> > [...]
> >> I like to propose the following to make overload resolution more
> >> precise.
> >> The following code shows my problem: (testet with gcc, clang, msvc)
> > [...]
> >> ab.f(p); // is ambiguous
> >
> > But it's name lookup that's ambiguous here, so you don't even get to
> > overload resolution, see http://eel.is/c++draft/class.member.lookup
> >
> >
> > Christof
> >
>
> Thank you Christof for your reply. My language lawyering is weak, as is my
> proposed solution. I could image that if the function name is not
> redefined in the derived class, name lookup should work as if the using
> declarations where explicitly stated, but i wish to not have to write
> them. It should not break code that works now. It would only behave
> differently for code that does not compile today.

The language rules treat such designs as weird. And by design
principle, when encountering a weird
situation, the language asks you to say what you mean, as opposed to
making a guess for you;
the expectation is that sometimes that guess might be good, sometimes
it might be horribly wrong,
and rather than go into that guesswork, you need to disambiguate explicitly.

There have been arguments trying to explain such ambiguities so that
if you change the signatures
of A::f and B::f, what you're calling might silently change because
the rules according to which the
guesswork decision would be made could lead to a different overload
resolution result. Silent behavior
changes can be nasty to track down if they cause a bug. This wouldn't
be the only way to get a silent
behavior change in C++, and avoiding those isn't done completely
consistently in C++'s design.

C++ also tries to avoid overloading across scopes. It doesn't do that
100% because various different namespace
scopes participate in overload resolution, but different base class
scopes don't. This is arguably done for programmer
sanity, which would be along the same lines as the refactoring argument.

I am not entirely convinced that the above captures every argument
that would be thrown against a suggestion to change such
rules old as time. Changing them requires strong rationale, and even
attempting to do so would best start with a archaeological
excavation of historic reasons for the current rules, not just a
glance at different examples that might be nice-to-have
in isolation.

Received on 2019-09-23 14:54:21