Search code examples
c++language-lawyer

Which rule disprefers qualification conversions during reference binding?


Consider

void foo(int*& r);              // (1)
void foo(const int* const& r);  // (2)

int main() {
    int* p;
    foo(p);
}

This calls (1) in all implementations I tested but I can't figure out what in the C++ standard requires this result.

[over.ics.ref]/1 implies that both reference bindings rank as identity conversions. int*& binds directly to an lvalue of type int* (obviously), and const int* const& also binds directly to an lvalue of type int*. (It doesn't convert the int* to a temporary const int* and bind to the temporary.)

Since both implicit conversion sequences are identity conversions, the overload resolution will be ambiguous unless there is a tie-breaker rule that distinguishes them.

[over.ics.rank]/3.2.5 might be the tie-breaker intended to apply to this situation:

S1 and S2 differ only in their qualification conversion ([conv.qual]) and yield similar types T1 and T2, respectively, where T1 can be converted to T2 by a qualification conversion.

However, it's not clear that it actually applies. There is not actually a qualification conversion in (2); the reference simply binds to the int* as if it were a const int*. Also, S1 and S2 yield reference types, and similarity does not apply to reference types (though I guess the definition still implies that a reference type is similar to itself).

Tie-breaker [over.ics.rank]/3.2.6 doesn't apply; one of its conditions is "the types to which the references refer are the same type except for top-level cv-qualifiers"; but const int* and int* differ in a non-top-level cv-qualifier.

I don't see any other tie-breaker rule that is remotely relevant. Did I miss something that implies that (1) is better than (2)?

The issue description of CWG1374 seems to allude to [over.ics.rank]/3.2.5 being relevant, so perhaps the issue is simply that that bullet's wording needs to be improved.


Solution

  • As user17732522 pointed out, the lack of a rule was an oversight while resolving CWG2352.

    I raised this with CWG, and it was agreed that there was an oversight. The result is CWG2803, which adds the missing wording.