This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115d. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2024-10-26
[Accepted as a DR at the June, 2024 meeting.]
P0847R7 (Deducing this) (approved October, 2021) added explicit-object member functions. Consider:
struct C { C(auto) { } }; void foo() { auto l = [](this C) { return 1; }; void (*fp)(C) = l; fp(1); // same effect as decltype(l){}() or decltype(l){}(1) ? }
Subclause 7.5.6.2 [expr.prim.lambda.closure] paragraph 8 does not address explicit object member functions:
The closure type for a non-generic lambda-expression with no lambda-capture whose constraints (if any) are satisfied has a conversion function to pointer to function with C++ language linkage (9.11 [dcl.link]) having the same parameter and return types as the closure type's function call operator. The conversion is to “pointer to noexcept function” if the function call operator has a non-throwing exception specification. The value returned by this conversion function is the address of a function F that, when invoked, has the same effect as invoking the closure type's function call operator on a default-constructed instance of the closure type. F is a constexpr function if...
Suggested resolution [SUPERSEDED]:
Change in 7.5.6.2 [expr.prim.lambda.closure] paragraph 8 as follows:
... The value returned by this conversion function isF is a constexpr function if... is an immediate function.
- for a lambda-expression whose parameter-declaration-clause has an explicit object parameter, the address of the function call operator (7.6.2.2 [expr.unary.op];
- otherwise, the address of a function F that, when invoked, has the same effect as invoking the closure type's function call operator on a default-constructed instance of the closure type.
[ Example:
struct C { C(auto) { } }; void foo() { auto a = [](C) { return 0; }; int (*fp)(C) = a; // OK fp(1); // same effect as decltype(a){}(1) auto b = [](this C) { return 1; }; fp = b; // OK fp(1); // same effect as (&decltype(b)::operator())(1) }-- end example ]
Change in 7.5.6.2 [expr.prim.lambda.closure] paragraph 11 as follows:
The value returned by any given specialization of this conversion function template isF is a constexpr function if...
- for a lambda-expression whose parameter-declaration-clause has an explicit object parameter, the address of the corresponding function call operator template specialization (7.6.2.2 [expr.unary.op]);
- otherwise, the address of a function F that, when invoked, has the same effect as invoking the generic lambda's corresponding function call operator template specialization on a default-constructed instance of the closure type.
CWG 2023-06-17
Requesting guidance from EWG with paper issue 1689.
Additional notes (October, 2023)
Additional examples demonstrating implementation divergence between clang and MSVC:
struct Any { Any(auto) {} }; auto x = [](this auto self, int x) { return x; }; auto y = [](this Any self, int x) { return x; }; auto z = [](this int (*self)(int), int x) { return x; }; int main() { x(1); y(1); z(1); int (*px)(int) = +x; // MSVC int (*py1)(int) = +y; // MSVC int (*py2)(Any, int) = +y; // Clang int (*pz1)(int) = +z; // MSVC int (*pz2)(int (*)(int), int) = +z; // Clang }
Additional notes (November, 2023)
Additional example:
auto c2 = [](this auto self) { return sizeof(self); }; struct Derived2 : decltype(c) { int value; } d2; struct Derived3 : decltype(c) { int value[10]; } d3;
For MSVC, d2() == 4 and d3() == 40, but +d2 and +d3 both point to functions returning 1.
EWG 2023-11-07
Move forward with option 1 "punt" from D3031 for C++26. A future paper can explore other solutions.
Proposed resolution (approved by CWG 2024-04-19):
Change the example in 7.5.6.1 [expr.prim.lambda.general] paragraph 6 as follows:
int i = [](int i, auto a) { return i; }(3, 4); // OK, a generic lambda int j = []<class T>(T t, int i) { return i; }(3, 4); // OK, a generic lambdaauto x = [](int i, auto a) { return i; }; // OK, a generic lambda auto y = [](this auto self, int i) { return i; }; // OK, a generic lambda auto z = []<class T>(int i) { return i; }; // OK, a generic lambda
Change in 7.5.6.2 [expr.prim.lambda.closure] paragraph 9 as follows:
The closure type for a non-generic lambda-expression with no lambda-capture and no explicit object parameter (9.3.4.6 [dcl.fct]) whose constraints (if any) are satisfied has a conversion function to pointer to function with C++ language linkage (9.11 [dcl.link]) having the same parameter and return types as the closure type's function call operator. ...
Change in 7.5.6.2 [expr.prim.lambda.closure] paragraph 10 as follows:
For a generic lambda with no lambda-capture and no explicit object parameter (9.3.4.6 [dcl.fct]), the closure type has a conversion function template to pointer to function. ...
CWG 2023-11-09
Keeping in review status in anticipation of a paper proposing reasonable semantics for the function pointer conversions.
EWG 2024-03-18
Progress with option #1 of P3031R0, affirming the direction of the proposed resolution.