badola
badola

Reputation: 870

Should we capture by const reference in lambda?

I have been reading Lambda capture as const reference?
It is an interesting feature, and sometimes I also wish this feature to exist, especially when I have huge data, which I need to access inside a lambda function.

My follow up questions -

Let us assume we can.
We assume [const &] as syntax to capture.

int x = 10;
auto lambda = [const & x](){ std::cout << x << std::endl; }; 
lambda(); // prints 10, great, as expected

x = 11;
lambda(); // should it print 11 or 10 ?

My intuition is that is should behave just like [&] but the captured value should not be allowed to modify.

template<typename Func>
void higher_order_function(int & x, Func f)
{
    f(); // should print 11
    x = 12;
    f(); // should print 12
}

void foo()
{
    int x = 10;
    auto c = [const & x] () { std::cout << x << std::endl; };

    c(); // should print 10
    x = 11;
    c(); // should print 11
    higher_order_function(x, c);

    auto d = [const & x] () { x = 13; }; // Compiler ERROR: Tried to assign to const qualified type 'const int &'!
} 

Upvotes: 2

Views: 3826

Answers (3)

JVApen
JVApen

Reputation: 11317

I've been wondering about this myself.
Since the operator() is const by default, I would assume that allowing const references is acceptable as well.

With the current standards(C++17), the closest I got to this behaviour is:

auto c = [ &x = std::as_const(x) ] () { std::cout << x << std::endl; };

Workaround in C++11/C++14 would be(thanks to Daniel for suggestion):

auto const & crx = x;
auto c = [ &crx ] () { std::cout << crx << std::endl; };

Upvotes: 4

max66
max66

Reputation: 66200

Maybe not exactly what you're looking for but... I suppose you can pass through a function that receive the same value by const reference.

Something as follows

template <typename T>
auto make_capture_const (T const & x)
 { return [&x](){ std::cout << x << std::endl; }; }

// ...

int x { 42 };

auto l = make_capture_const(x);

l();

If you try to modify x inside the lambda

std::cout << x++ << std::endl;

you should get an error.

As you can see, from, this solution you get that x can't be modified inside the lambda but the lambda is influenced from the value changes outside

   int x { 42 };

   auto l = make_capture_const(x);

   l();  // print 42

   x = 43;

   l();  // print 43

IMHO, an hypothetic [const &] capture syntax should works in the same way. But I understand that is highly questionable.

Upvotes: 1

Daniel Langr
Daniel Langr

Reputation: 23497

lambda(); // should it print 11 or 10 ?

I don't understand why it should print 10. Consider lambda being just an instance of some anonymous class. Making it a normal class, it should look like:

class Lambda {
   public:
      Lambda(const int & i) : i_(i) { }
      void operator()() { std::cout << i_ << std::endl; }
   private:
      const int & i_;
 };

int x = 10;
Lambda lambda(x);
lambda(); // prints 10, great, as expected

x = 11;
lambda(); // should it print 11 or 10 ?

The meaning of const reference here is only that you cannot modify x through i_ member reference variable.


A simlpler scenario:

int x = 10;
const int & crx = x;
x++;
std::cout << crx << std::endl; // prints 11

Upvotes: 4

Related Questions