This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2025-04-13


2803. Overload resolution for reference binding of similar types

Section: 12.2.4.2.5  [over.ics.ref]     Status: DRWP     Submitter: Brian Bi     Date: 2023-06-14

[Accepted as a DR at the March, 2024 meeting.]

Consider:

 int foo(int*& r); // #1 int foo(const int* const& r); // #2 int *p; int x = foo(p); 

Both #1 and #2 perform direct reference binding; no qualification conversions are involved. Despite the lack of a rule, implementations prefer #1 over #2.

Proposed resolution (approved by CWG 2023-11-10):

  1. Change in 12.2.4.2.5 [over.ics.ref] paragraph 1 as follows:

    When a parameter of reference type "reference to cvT" binds directly (9.5.4 [dcl.init.ref]) to an argument expression, the implicit conversion sequence is the identity conversion, unless:
    • If the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base conversion (12.2.4.2 [over.best.ics]).
    • Otherwise, if T is a function type, or if the type of the argument is possibly cv-qualified T, or if T is an array type of unknown bound with element type U and the argument has an array type of known bound whose element type is possibly cv-qualified U, the implicit conversion sequence is the identity conversion. [ Note: When T is a function type, the type of the argument may differ only by the presence of noexcept. -- end note]
    • Otherwise, the implicit conversion sequence is a qualification conversion.

    [Example 1: ... —end example]

    If the parameter binds directly to the result of applying a conversion function to the argument expression, the implicit conversion sequence is a user-defined conversion sequence (12.2.4.2.3 [over.ics.user]) whose second standard conversion sequence is either an identity conversion or, if the conversion function returns an entity of a type that is a derived class of the parameter type, a derived-to-base conversiondetermined by the above rules.
  2. Change in 12.2.4.3 [over.ics.rank] bullet 3.2.5 as follows:

    • S1 and S2 differ only in their qualification conversion (7.3.6 [conv.qual]) and yield similar types T1 and T2, respectively (where a standard conversion sequence that is a reference binding is considered to yield the cv-unqualified referenced type), where T1 can be converted to T2 by a qualification conversionand T2 are not the same type, and const T2 is reference-compatible with T1 (9.5.4 [dcl.init.ref]). [Example 5:
       int f(const volatile int *); int f(const int *); int i; int j = f(&i); // calls f(const int*)  int g(const int*); int g(const volatile int* const&); int* p; int k = g(p); // calls g(const int*)
      -- end example] or, if not that,
  3. Change in 12.2.4.3 [over.ics.rank] bullet 3.2.6 as follows:

    • S1 and S2 include reference bindingsbind "reference to T1" and "reference to T2", respectively (9.5.4 [dcl.init.ref]), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 referswhere T1 and T2 are not the same type, and T2 is reference-compatible with T1. [Example 6: ...
       int h1(int (&)[]); int h1(int (&)[1]); int h2(void (&)()); int h2(void (&)() noexcept); void g2() { int a[1]; h1(a); // calls h1(int (&)[1]) extern void f2() noexcept; h2(f2); // calls h2(void (&)() noexcept) } 
      -- end example ]


close