Created on 2023-10-05.00:00:00 last changed 2 days ago
Proposed resolution (approved by CWG 2024-10-11):
Change in 12.2.4.2.5 [over.ics.ref] paragraph 1 as follows:
When a parameter of type “reference to cvT” binds directly (9.4.4 [dcl.init.ref]) to an argument expression:[Example 1:
- If the argument expression has a type that is a derived class of the parameter type, the implicit conversion sequence is a derived-to-base conversion (12.2.4.2 [over.best.ics]).
- Otherwise,
if T is a function type, orif 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 1: When T is a function type, the type of the argument can differ only by the presence of noexcept. —end note]- Otherwise, if T is a function type, the implicit conversion sequence is a function pointer conversion.
- Otherwise, the implicit conversion sequence is a qualification conversion.
struct A {}; struct B : public A {} b; int f(A&); int f(B&); int i = f(b); // calls f(B&), an exact match, rather than f(A&), a conversion
void g() noexcept; int h(void (&)() noexcept); // #1 int h(void (&)()); // #2 int j = h(g); // calls #1, an exact match, rather than #2, a function pointer conversion—end example]
Change in 12.2.4.3 [over.ics.rank] bullet 3.2.6 as follows:
int f(const int &); int f(int &); int g(const int &); int g(int); int i; int j = f(i); // calls f(int &) int k = g(i); // ambiguous struct X { void f() const; void f(); }; void g(const X& a, X b) { a.f(); // calls X::f() const b.f(); // calls X::f() } int h1(int (&)[]); int h1(int (&)[1]);int h2(void (&)()); int h2(void (&)() noexcept);void g2() { int a[1]; h1(a);extern void f2() noexcept; h2(f2);}
CWG 2024-06-26
Binding a reference to a function should not be considered an identity conversion if it strips a non-throwing exception specification. This amendment removes the ambiguity for the first example and makes the second example ambiguous, which is desirable.
Consider:
void f() noexcept {}
void g(void (*)() noexcept) {}
void g(void (&)()) {}
int main() {
g(f); // error: ambiguous
}
In contrast:
void f() noexcept {} void g(void (*)()) {} void g(void (&)()) {} // #1 int main() { g(f); // OK, calls #1 }
In both cases, binding void(&)() to void() noexcept is considered an identity conversion, without further disambiguation by 12.2.4.3 [over.ics.rank].
History | |||
---|---|---|---|
Date | User | Action | Args |
2024-11-18 17:53:08 | admin | set | status: tentatively ready -> ready |
2024-10-11 20:31:34 | admin | set | status: review -> tentatively ready |
2024-10-01 09:22:29 | admin | set | messages: + msg7828 |
2024-10-01 09:22:29 | admin | set | status: drafting -> review |
2024-06-28 19:56:12 | admin | set | messages: + msg7762 |
2024-06-28 19:56:12 | admin | set | status: open -> drafting |
2023-10-05 00:00:00 | admin | create |