Date: Sat, 21 Jun 2025 22:09:15 -0400
> For all intents and purposes, a lambda that captures local variables
> by reference is a part of the function it is within. So why does it
> need to capture the variable as `const`? If the object wasn't already
> `const`, why does the lambda need non-modifying access to it? The rest
> of the function could modify it, so why does there need to be special
> syntax to prevent one part of that function from modifying it?
As a stylistic rule, the codebase I'm working on prefers `const`ness by
default and tries to avoid mutability when it isn't necessary (we have
`misc-const-correctness` in clang-tidy turned on). It's inherently helpful
to know that repeatedly calling a lambda *won't* modify a variable that has
been captured. Normally I would capture-by-value to guarantee idempotence,
but that isn't good for performance-critical code.
Other times, I create a template lambda and use it in a fold expression for
iteration. If I'm unsure of the concrete type, this allows the compiler to
check the methods I am calling are `const`.
I believe this is somewhat widespread because cppreference.com lists
captures by const reference as a use case of the current syntax.[1]
There's also precedent in style guides for encapsulating modification
behaviour within a local function by using lambdas. ES.28 of the C++ Core
Guidelines recommends immediately-invoked lambdas for initializing local
variables because it allows for designating those variables as `const`.[2]
If you're not already sold on "const everywhere" this likely isn't useful,
but it does solve a problem I am currently having.
[1] "This also makes it possible to capture by const reference, with &cr =
std::as_const(x) or similar."
https://en.cppreference.com/w/cpp/language/lambda.html#Lambda_capture
[2]
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-lambda-init
On Sat, Jun 21, 2025 at 9:15 PM Jason McKesson via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Sat, Jun 21, 2025 at 9:07 PM JJ Marr via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> > For function parameters that are slow to copy, we have const references.
> For lambda captures that are slow to copy, we do not have an easy
> equivalent.
> >
> > The easiest way to do this is:
> >
> > ```cpp
> > #import <functional>
> > #import <utility>
> > int var;
> > [newVar = std::cref(var)](){
> > // body
> > };
> >
> > [&newVar = std::as_const(var)](){
> > // body
> > };
> > ```
> >
> > This requires importing the functional (for std::cref) or utility (for
> std::as_const) headers. It also requires the creation of a new identifier,
> possibly with a different name to avoid variable shadowing warnings.
> >
> > We should be able to `const`-qualify a lambda capture. For captures
> by-value on a non-mutable lambda, this would have no effect because
> value-captures cannot be modified. For reference captures or a mutable
> lambda, this would have the same behaviour as `const` on any other
> identifier (cannot modify/call non-const members/etc). A possible syntax
> would be:
> >
> > ```cpp
> > [const &var](){
> > // body
> > };
> > ```
> >
> > Open questions:
> > * Should we allow for other/arbitrary qualifiers? i.e. volatile?
> > * Can we apply qualifiers to a default capture? e.g.:
> >
> > ```cpp
> > [const &](){
> > // body
> > };
> > ```
> >
> > Appreciate feedback on whether this is a good enough idea to turn into a
> proposal.
>
> For all intents and purposes, a lambda that captures local variables
> by reference is a part of the function it is within. So why does it
> need to capture the variable as `const`? If the object wasn't already
> `const`, why does the lambda need non-modifying access to it? The rest
> of the function could modify it, so why does there need to be special
> syntax to prevent one part of that function from modifying it?
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
> by reference is a part of the function it is within. So why does it
> need to capture the variable as `const`? If the object wasn't already
> `const`, why does the lambda need non-modifying access to it? The rest
> of the function could modify it, so why does there need to be special
> syntax to prevent one part of that function from modifying it?
As a stylistic rule, the codebase I'm working on prefers `const`ness by
default and tries to avoid mutability when it isn't necessary (we have
`misc-const-correctness` in clang-tidy turned on). It's inherently helpful
to know that repeatedly calling a lambda *won't* modify a variable that has
been captured. Normally I would capture-by-value to guarantee idempotence,
but that isn't good for performance-critical code.
Other times, I create a template lambda and use it in a fold expression for
iteration. If I'm unsure of the concrete type, this allows the compiler to
check the methods I am calling are `const`.
I believe this is somewhat widespread because cppreference.com lists
captures by const reference as a use case of the current syntax.[1]
There's also precedent in style guides for encapsulating modification
behaviour within a local function by using lambdas. ES.28 of the C++ Core
Guidelines recommends immediately-invoked lambdas for initializing local
variables because it allows for designating those variables as `const`.[2]
If you're not already sold on "const everywhere" this likely isn't useful,
but it does solve a problem I am currently having.
[1] "This also makes it possible to capture by const reference, with &cr =
std::as_const(x) or similar."
https://en.cppreference.com/w/cpp/language/lambda.html#Lambda_capture
[2]
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-lambda-init
On Sat, Jun 21, 2025 at 9:15 PM Jason McKesson via Std-Proposals <
std-proposals_at_[hidden]> wrote:
> On Sat, Jun 21, 2025 at 9:07 PM JJ Marr via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
> >
> > For function parameters that are slow to copy, we have const references.
> For lambda captures that are slow to copy, we do not have an easy
> equivalent.
> >
> > The easiest way to do this is:
> >
> > ```cpp
> > #import <functional>
> > #import <utility>
> > int var;
> > [newVar = std::cref(var)](){
> > // body
> > };
> >
> > [&newVar = std::as_const(var)](){
> > // body
> > };
> > ```
> >
> > This requires importing the functional (for std::cref) or utility (for
> std::as_const) headers. It also requires the creation of a new identifier,
> possibly with a different name to avoid variable shadowing warnings.
> >
> > We should be able to `const`-qualify a lambda capture. For captures
> by-value on a non-mutable lambda, this would have no effect because
> value-captures cannot be modified. For reference captures or a mutable
> lambda, this would have the same behaviour as `const` on any other
> identifier (cannot modify/call non-const members/etc). A possible syntax
> would be:
> >
> > ```cpp
> > [const &var](){
> > // body
> > };
> > ```
> >
> > Open questions:
> > * Should we allow for other/arbitrary qualifiers? i.e. volatile?
> > * Can we apply qualifiers to a default capture? e.g.:
> >
> > ```cpp
> > [const &](){
> > // body
> > };
> > ```
> >
> > Appreciate feedback on whether this is a good enough idea to turn into a
> proposal.
>
> For all intents and purposes, a lambda that captures local variables
> by reference is a part of the function it is within. So why does it
> need to capture the variable as `const`? If the object wasn't already
> `const`, why does the lambda need non-modifying access to it? The rest
> of the function could modify it, so why does there need to be special
> syntax to prevent one part of that function from modifying it?
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2025-06-22 02:09:30