Passing by constant reference in the lambda capture list

22,819

Solution 1

You can create and capture const references explicitly:

int x = 42;
const int& rx = x;
auto l = [&rx]() {
    x = 5; // error: 'x' is not captured
    rx = 5; // error: assignment of read-only reference 'rx'
};

Solution 2

The capture list is limited in what can be captured; basically by-value or by-reference (named or by default), the this pointer and nothing.

From the cppreference;

capture-list - a comma-separated list of zero or more captures, optionally beginning with a capture-default. Capture list can be passed as follows (see below for the detailed description):

  • [a,&b] where a is captured by value and b is captured by reference.
  • [this] captures the this pointer by value
  • [&] captures all automatic variables odr-used in the body of the lambda by reference
  • [=] captures all automatic variables odr-used in the body of the lambda by value
  • [] captures nothing

You could create local const& to all the object you wish to capture and use those in the lambda.

#include <iostream>

using namespace std;

int main()
{
    int a = 5;
    const int& refa = a;
    const int b = [&]() -> int {
        //refa = 10; // attempts to modify this fail
        return refa;
    }();
    cout << a << " " << b << endl;
}

The capture could be either for all the references, or an explicit list what is required;

const int b = [&refa]()

Another alternative is not to capture the local variables at all. You then create a lambda that accepts as arguments the variables you need. It may be more effort as the local variable count grows, but you have more control over how the lambda accepts its arguments and is able to use the data.

auto lambda = [](const int& refa /*, ...*/) { */...*/ }
lambda(...);

Solution 3

You can capture a constant reference to an object, not an object itself:

A a;
const A& ref_a = a;

const double defaultAmount = [&]{
    ref_a.smth();
}();

Solution 4

Sadly the C++11 grammar does not allow for this, so no.

Share:
22,819
P45 Imminent
Author by

P45 Imminent

I work for an asset management firm in Mayfair, London.

Updated on July 09, 2022

Comments

  • P45 Imminent
    P45 Imminent almost 2 years

    I'm building a lambda function that requires access to a fair number of variables in the context.

    const double defaultAmount = [&]{
        /*ToDo*/
    }();
    

    I'd rather not use [=] in the list as I don't want lots of value copies to be made.

    I'm concerned about program stability if I use [&] since I don't want the lambda to modify the capture set.

    Can I pass by const reference? [const &] doesn't work.

    Perhaps a good compiler optimises out value copies, so [=] is preferable.

  • Angew is no longer proud of SO
    Angew is no longer proud of SO almost 9 years
    If the subroutine requires "a fair number of variables in the context," making a proper function and passing them all is probably precisely what the OP is trying to avoid.