Description
In #2288 we attempted to clarify ambiguous conversion sequences, but I think there are a couple problems left unaddressed.
Consider the following:
#include <initializer_list>
struct A { A(int); };
struct B { B(int); };
struct C
{
C(A);
C(B);
};
struct D
{
D(C); // #1
D(std::initializer_list<A>); // #2
};
D d({0}); // calls #2
[over.best.ics] p10 says:
For the purpose of ranking implicit conversion sequences as described in [over.ics.rank], the ambiguous conversion sequence is treated as a user-defined conversion sequence that is indistinguishable from any other user-defined conversion sequence.
In the above example, the ICS from {0}
to C
is the ambiguous conversion sequence (ACS) and the ICS from {0}
to std::initializer_list<A>
is a user-defined conversion sequence (UCS). Now with respect to the quoted paragraph: is the ACS considered to be indistinguishable from any other UCS regardless of [over.ics.rank], or will the rules in [over.ics.rank] p3 apply to disambiguate in this situation, making the conversion to std::initializer_list<A>
a better ICS? I think the intent is pretty clear that the latter is true, but the wording does not make this clear.
For this issue, I think the following change would be sufficient:
Change [over.best.ics] p10 sentence 2:
For the purpose of ranking implicit conversion sequences as described in [over.ics.rank], the ambiguous conversion sequence
is treated asconsidered to be a user-defined conversion sequencethat is indistinguishable from anyof the same form as every other user-defined conversion sequence.
As for the other issue, consider the first sentence of [over.best.ics] p10:
If there are multiple well-formed implicit conversion sequences converting the argument to the parameter type [...]
First off, this wording seems to be at odds with the note in [over.best.ics] p2, particularly with the "well-formed" bit which I take to say that the application of that sequence of conversions must be be well-formed, most notably with respect to access control and whether a function is deleted. In addition to this, it's unclear what it even means for there to be multiple implicit conversion sequences. For example:
struct A
{
A(int); // #1
A(long); // #2
};
void f(A);
f(0); // not ill-formed
Arguably, there are "multiple well-formed implicit conversion sequences" here, both of which are user-defined conversion sequences. Here the intent is obvious as to what should occur.
There are two ways to approach this: either a substantial overhaul as to how we chose the ICS for a particular function parameter, or a smaller scale patch. For the latter, I suggest the following:
Change [over.best.ics] p10 sentence 1:
If there are
multiple well-formedat least two implicit conversion sequencesS1
andS2
converting the argument to the parameter type such thatS1
is indistinguishable fromS2
, the implicit conversion sequence associated with the parameter is defined to be the unique conversion sequence designated the ambiguous conversion sequence.
As for the more substantial change, it would entail forming a set of candidate conversion sequences from each argument to its respective parameter in each applicable subclause, and then determining if the resultant conversion from the argument to the parameter is either formed, not formed, or ambiguous.