Title
Conversion to function pointer for lambda with explicit object parameter
Status
drwp
Section
7.5.6.2 [expr.prim.lambda.closure]
Submitter
Barry Revzin

Created on 2022-02-14.00:00:00 last changed 4 days ago

Messages

Date: 2024-04-18.22:29:47

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.

Date: 2024-04-27.16:38:35

Proposed resolution (approved by CWG 2024-04-19):

  1. 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 lambda
      auto 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
    
    
  2. 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. ...
  3. 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. ...
Date: 2023-11-15.00:00:00

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.

Date: 2023-10-15.00:00:00

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
  }
Date: 2023-10-26.08:01:37

CWG 2023-06-17

Requesting guidance from EWG with paper issue 1689.

Date: 2023-11-09.14:37:14

Suggested resolution [SUPERSEDED]:

  1. Change in 7.5.6.2 [expr.prim.lambda.closure] paragraph 8 as follows:

    ... The value returned by this conversion function is
    • 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.
    F is a constexpr function if... is an immediate function.

    [ 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 ]

  2. 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 is
    • 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.
    F is a constexpr function if...
Date: 2024-06-15.00:00:00

[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...
History
Date User Action Args
2024-12-17 09:54:02adminsetstatus: dr -> drwp
2024-07-20 13:52:34adminsetstatus: ready -> dr
2024-06-25 12:54:46adminsetstatus: tentatively ready -> ready
2024-04-27 16:38:35adminsetstatus: review -> tentatively ready
2023-11-09 23:04:42adminsetmessages: + msg7508
2023-11-09 23:04:42adminsetmessages: + msg7507
2023-11-09 14:37:14adminsetstatus: open -> review
2023-11-03 14:17:06adminsetmessages: + msg7491
2023-10-26 08:01:37adminsetmessages: + msg7483
2023-10-26 08:01:37adminsetmessages: + msg7482
2023-10-26 08:01:37adminsetstatus: review -> open
2023-06-20 06:44:53adminsetstatus: open -> review
2022-04-02 13:19:03adminsetmessages: + msg6786
2022-02-14 00:00:00admincreate