C++ Logo

std-discussion

Advanced search

Re: [over.ics.rank] standard conversion tie-breakers from different source types

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Tue, 10 Jan 2023 22:00:28 +0000
On Tue, 10 Jan 2023 17:47:38 +0000
Edward Catmur via Std-Discussion <std-discussion_at_[hidden]>
wrote:

> On Tue, 10 Jan 2023 at 17:05, Brian Bi <bbi5291_at_[hidden]> wrote:
>
> >
> >
> > On Tue, Jan 10, 2023 at 11:24 AM Edward Catmur via Std-Discussion <
> > std-discussion_at_[hidden]> wrote:
> >
> >>
> >>
> >> On Tue, 10 Jan 2023 at 15:57, language.lawyer--- via
> >> Std-Discussion < std-discussion_at_[hidden]> wrote:
> >>
> >>> > I would like an example of a function call to an overloaded
> >>> > function, where the most viable function is determined by the
> >>> > rules listed from [over.ics.rank]/4.4.5 to
> >>> > [over.ics.rank]/4.4.8:
> >>> >
> >>> > https://timsong-cpp.github.io/cppwp/n4868/over.ics.rank#4.4.5
> >>> >
> >>> > These are four different tie-breakers for ranking standard
> >>> > conversions from different source types, assuming the following
> >>> > class hierarchy:
> >>> >
> >>> > struct A {}; struct B : C {}; struct C : B {};
> >>> >
> >>> > (4.4.5) conversion of B* to A* is better than conversion of C*
> >>> > to A*, (4.4.6) binding of an expression of type B to a
> >>> > reference to type A is better than binding an expression of
> >>> > type C to a reference to type A, (4.4.7) conversion of B::* to
> >>> > C::* is better than conversion of A::* to C::*, and
> >>> > (4.4.8) conversion of B to A is better than conversion of C to
> >>> > A.
> >>> >
> >>> > The note says that these are only used for tie-breakers in the
> >>> > second conversion sequence of user-defined conversions:
> >>> >
> >>> > https://timsong-cpp.github.io/cppwp/n4868/over.ics.rank#note-1
> >>>
> >>> I think it is just a wrong Note.
> >>> CD2 (November 96
> >>> https://www.open-std.org/jtc1/sc22/wg21/docs/wp/html/cd2/over.html#over.ics.rank)
> >>> Note was saying:
> >>> > [Note: it is necessary to compare conversions with different
> >>> > target types in the context of an initialization by
> >>> > user-defined conver- sion; see _over.match.best_. ]
> >>>
> >>> Which also seems not 100% correct (incomplete?), because it
> >>> mentions (only?) target, and not source types.
> >>>
> >>> The next WP (Oct'97
> >>> https://www.open-std.org/jtc1/sc22/wg21/docs/wp/html/oct97/over.html#over.ics.rank)
> >>> Note gained its current (defective) wording.
> >>>
> >>> (The bullets themselves have been added by
> >>> https://www.open-std.org/JTC1/sc22/wg21/docs/papers/1995/N0661.asc)
> >>>
> >>> So, ecatmur's example seems to be relevant here, except that the
> >>> Note is not about the second standard conversion sequence after
> >>> different user conversion functions, but about
> >>> https://timsong-cpp.github.io/cppwp/n4868/over.match.best#general-2.2
> >>>
> >>
> >> Ah. So, currently, the Note says:
> >>
> >> > Compared conversion sequences will have different source types
> >> > only in
> >> the context of comparing the second standard conversion sequence
> >> of an initialization by user-defined conversion (see
> >> [over.match.best]); in all other contexts, the source types will
> >> be the same and the target types will be different.
> >>
> >> Whereas [over.match.best.general]/2.2 says:
> >>
> >> > ... the context is an initialization by user-defined conversion
> >> > (see
> >> [dcl.init], [over.match.conv], and [over.match.ref]) and the
> >> standard conversion sequence from the return type of F1 to the
> >> destination type (i.e., the type of the entity being initialized)
> >> is a better conversion sequence than the standard conversion
> >> sequence from the return type of F2 to the destination type ...
> >>
> >> Would it make sense to amend the latter to mention the second SCS?
> >> i.e.,
> >> > ... the context is an initialization by user-defined conversion
> >> > (see
> >> [dcl.init], [over.match.conv], and [over.match.ref]) and the
> >> <ins>second</ins> standard conversion sequence <ins>of ICSj(F1)
> >> (i.e., that</ins> from the return type of F1 to the
> >> <del>destination type (i.e.,</del> the type of the entity being
> >> initialized) is a better conversion sequence than the
> >> <ins>second</ins> standard conversion sequence <del>from the
> >> return type of F2 to the destination type</del><ins>of
> >> ICSj(F2)</ins> ...
> >
> > I think if we need to clarify it, we should just add a note.
> > Changing normative wording always risks unforeseen consequences.
> >
>
> Ah, Well, should we change the offending Note (to [over.ics.rank])
> then?
>
> > Compared conversion sequences will have different source types
> > only in
> the context of <del>comparing the second standard conversion sequence
> of</del> an initialization by user-defined conversion<ins>,
> specifically when comparing the standard conversion sequence from the
> return type of a viable function to the destination type</ins> (see
> [over.match.best]); in all other contexts, the source types will be
> the same and the target types will be different.

I might have found a case where no user-defined conversions are
involved:

struct A {
    void foo();
};

struct B : A {
    using A::foo;
    void foo(int);
};

struct C : B {};

void f(void (C::*)()); // 1
void f(void (C::*)(int)); // 2

int main() {
    // if conversion from void (B::*)(int) to void (C::*)(int)
    // is better than void (A::*)() to void (C::*)()
    // then the second overload must be called
    f(&B::foo);
}

I think https://eel.is/c++draft/over.ics.rank#4.5.7 applies, although
only gcc implements this.

https://godbolt.org/z/7corz5539

Anyway, if this applies, then the note wrongly states that these only
apply in the context of user-defined conversions.

Cheers,
Lénárd

Received on 2023-01-10 22:00:35