On Wed, 2025-10-01 at 10:19 -0400, Arthur O'Dwyer via Std-Proposals wrote:
On Wed, Oct 1, 2025 at 2:44 AM Rhidian De Wit <rhidiandewit@gmail.com> wrote:
Hi Arthur,

Thanks for the response, I'll take a look at making a PR in the Core Guidelines to clarify the example a bit further.

I wasn't very familiar yet with the explicit parameter object, especially not in lambdas, and after reading a bit about I did find that you can refer to the captured variables in a lambda by using the `self` parameter you declare: https://godbolt.org/z/9d1oPv9fG
Now, this is pretty painful syntax, as we'd constantly have to type `std::forward_like<decltype(self)>(value)` to be able to use our values safely.


The good news: you don't have to, and should not, use `std::forward_like<decltype(self)>`, because `self` is not a forwarding reference. Never forward things that aren't forwarding references!
Because `decltype(self)` is a prvalue type (namely `Lambda`), therefore `std::forward<decltype(self)>(...)` expands to `static_cast<Lambda&&>(...)`, and `std::forward_like<decltype(self)>(...)` expands to basically `std::move(...)`.

The better news: Hm, you seem to have discovered that lambdas with explicit `this` parameters already work the way I was hoping they could be made to!
    auto lambda = [x=2](this auto self) { return &x; };
    int *px = lambda();  // return a (dangling) pointer into `self`'s captures, not a pointer into `lambda`'s captures!
Godbolt: https://godbolt.org/z/Gve3frTh3

Looks like this comes from
https://eel.is/c++draft/expr.prim.id#unqual-4.sentence-1 (says what type an expression like `x` has, in terms of the type of `self`; but not what value it has)
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0847r7.html#wording-in-expr

I can't find where this is normatively specified; the closest I've gotten so far is
https://eel.is/c++draft/expr.prim.lambda#capture-11
"Every id-expression within the compound-statement of a lambda-expression [...] is transformed into an access to the corresponding unnamed data member of the closure type" — but this seems like a category error to me; it should be saying something about the corresponding unnamed data member of some particular object (not some type), and in our example above, we need to ensure that that particular object is specifically the by-value parameter `self` and not some other object. And:
"the type of [an expression such as `x`] is the type of a class member access expression naming the non-static data member that would be declared for such a capture in the object parameter of the function call operator of E" — but this describes only the expression's type; it doesn't specify how to compute the expression's value.

But, on the assumption that it's supposed to work this way — and all three compiler vendors seem to agree it is —
it looks like your problem can be solved by simply adding `(this auto)` to your coroutine lambdas' signatures. (You don't need to, and therefore probably shouldn't, give that parameter any name.) It might even be worth creating a macro something like
  #define DEFERRED this auto
so such lambdas really stand out:
  int x = 1;
  auto lambda = [&](DEFERRED, int y) -> Deferred { co_return x + y; };
  co_await lambda();


This is incredibly helpful. In Seastar it's termed the "lambda coroutine fiasco" and there are bad workarounds for it, but this seems to exactly solve the problem.