Since writing my previous post that provides an introduction to lambdas in C++ I’ve wanted to write a post that digs deeper into how they work. I’ve read a bit and experimented. As part of my research to teach myself how they work I’ve found a few good write-ups detailing how they work. Given that these fine folks have already done a wonderful job of describing how lambdas work replete with examples and links to Compiler Explorer or CPP Insights, I thought I’d give just a brief description then leave it up to folks who’ve already put in the hard work.
But How Do Lambdas Actually Work?
There is one major thing (with 3 “states”) that complicate what a lambda can do: capturing variables. The three versions of this are:
- No captures
- Capture by value
- Capture by reference
Regardless of these three versions of what a lambda can do it doesn’t change the nature of what a lambda is roughly equivalent to: A temporary class that does nothing but overload operator(). Writing the code this way yourself would typically be called a “functor”.
What does this look like, you ask? Here is the example of a functor and a lambda capturing by reference pulled from the write up of Natasha Jarus.
class Functor {
public:
Functor(int& x): m_x(x) {}
int operator()(int a) {
return a + m_x++;
}
private:
int& m_x;
};
int main() {
int x = 3;
auto lambda = [&] (int a) { return a + x++; };
Functor functor(x);
volatile int y1 = functor(5);
volatile int y2 = lambda(5);
return 0;
}
This example shows the functor taking x by reference as part of its constructor where as the lambda does the same inline (implicitly since the [&] pulls everything local by reference).
Write-Ups Describing Lambda Internals
With this example shown I’ll leave the rest of the description up to the following write-ups. If there are more write-ups that give more details please let me know and I’ll include them here!