C++ lambda
MAIN REFERENCE: Modern C++ Features (Anthony Calandra), overview C++20/17/14/11 (MIT)
QUICK NTOES
c++ 11 (introduced)
[<CAPTURE>] (<params>) -> <return type> {/* BODY */}
[]
no capture[=]
and[&]
: capture local objects in scope by value or reference. Can specify objects by name e.g.[a, &b]
[this]
: capturethis
by reference
c++ 14
- generic lambda expressions (
auto
initializer)auto identity = [](auto x) { return x; }; int three = identity(3); // 3 string foo = identity("foo"): // "foo"
- labda capture initializers. The capture introduces new name inside the lambda
body. The expression is evaluated when lambda is created (not when its invoked)>
int factory(int i) {return i * 10; } auto f = [x = factory(2)] {return x;} // x is a new name, not a local obj // x = 0 is evaluated ONCE at creation. Analoge static variable in // function auto generator = [x = 0] () mutable { return x++; }; auto a = generator(); // 0 auto b = generator(); // 1 auto c = generator(); // 2
c++ 17
- constexpr lambda compile time lambdas using constexpr.
auto identity = [](int n) constexpr { return n; }; static_assert(identity(123) == 123); constexpr auto add = [](int x, int y) { auto L = [=] { return x; }; auto R = [=] { return y; }; return [=] { return L() + R(); }; }; static_assert(add(1, 2)() == 3); constexpr int addOne(int n) { return [n] { return n + 1; }(); } static_assert(addOne(1) == 2)
- lambda capture
this
by value.*this
(C++17) will now make a copy of the current object, whilethis
(C++11) continues to capture by reference.
c++ 20
- template syntax for lambda
auto f = []<typename T>(std::vector<T> v) { // ... };
- lambda capture of parameter pack
template <typename... Args> auto f(Args&&... args){ // BY VALUE: return [...args = std::forward<Args>(args)] {}; // BY REFERENCE return [&...args = std::forward<Args>(args)] { }
- Deprecate implicit capture of this: Implicitly capturing this in a lambda
capture using [=] is now deprecated; prefer capturing explicitly using
[=,this]
or[=, *this]
.
ALL IN ONE EXAMPLE
#include <iostream>
int main() {
int x = 1;
auto getX = [=](void) -> int { return x; };
// same as [=] {return x;};
// illegal: [=] -> int {return x;};
auto errX = [=](void) mutable -> int { x += 1; return x; };
// without `mutable` it's not allowed to modify x value (even it has no effect
// on the original x.
auto addX = [=](int y) { return x + y; };
// do not need mutable to modify via reference.
auto incX = [&](int y) { x += y; };
auto refX = [&]() -> int & { return x; };
std::cout << getX() << std::endl; // 1
std::cout << addX(1) << std::endl; // 2
errX();
std::cout << x << std::endl; // 1
incX(100);
std::cout << getX() << std::endl; // 1 because value captured before inc
std::cout << x << std::endl; // 101 x is modified via reference
auto& refx = refX(); // & is important, otherwise auto deduces
// the reference into int and performs copy
refx += 42;
std::cout << getX() << std::endl; // 1 (old captured value)
std::cout << x << std::endl; // 101 (why????)
return 0;
}