Lambda functions (since C++11)

From cppreference.com
 
 
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements
Jump statements
Functions
function declaration
lambda function declaration
function template
inline specifier
exception specifications (deprecated)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
decltype specifier (C++11)
Specifiers
cv specifiers
storage duration specifiers
constexpr specifier (C++11)
auto specifier (C++11)
alignas specifier (C++11)
Initialization
Literals
Expressions
alternative representations
Utilities
Types
typedef declaration
type alias declaration (C++11)
attributes (C++11)
Casts
implicit conversions
const_cast conversion
static_cast conversion
dynamic_cast conversion
reinterpret_cast conversion
C-style and functional cast
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
class template
function template
template specialization
parameter packs (C++11)
Miscellaneous
Inline assembly
 

Constructs a closure: an unnamed function object capable of capturing variables in scope.

Contents

[edit] Syntax

[ capture ] ( params ) mutable exception attribute -> ret { body } (1)
[ capture ] ( params ) -> ret { body } (2)
[ capture ] ( params ) { body } (3)
[ capture ] { body } (4)

1) Full declaration

2) Declaration of a const lambda: the objects captured by copy cannot be modified.

3) Omitted trailing-return-type: the return type of the closure's operator() is deduced according to the following rules:

  • if the body consists of the single return statement, the return type is the type of the returned expression (after rvalue-to-lvalue, array-to-pointer, or function-to-pointer implicit conversion)
  • otherwise, the return type is void

4) Omitted parameter list: function takes no arguments, as if the parameter list was ()

[edit] Explanation

mutable - allows body to modify the parameters captured by copy, and to call their non-const member functions
exception - provides the exception specification or the noexcept clause for operator() of the closure type
attribute - provides the attribute specification for operator() of the closure type
capture - specifies which symbols visible in the scope where the function is declared will be visible inside the function body.

A list of symbols can be passed as follows:

  • [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 mentioned in the body of the lambda by reference
  • [=] captures all automatic variables mentioned in the body of the lambda by value
  • [] captures nothing
params - The list of parameters, as in named functions
ret - Return type. If not present it's implied by the function return statements ( or void if it doesn't return any value)
body - Function body


The lambda expression constructs an unnamed temporary object of unique unnamed non-union non-aggregate type, known as closure type, which has the following members:

ClosureType::operator()

ret operator()(params) const { body }
(the keyword mutable was not used)
ret operator()(params) { body }
(the keyword mutable was used)

Executes the body of the lambda-expression, when invoked. When accessing a variable, accesses its captured copy (for the entities captured by copy), or the original object (for the entities captured by reference). Unless the keyword mutable was used in the lambda-expression, the objects that were captured by copy are non-modifiable from inside this operator().

Dangling references

If an entity is captured by reference, implicitly or explicitly, and the function call operator of the closure object is invoked after the entity's lifetime has ended, undefined behavior occurs. The C++ closures do not extend the lifetimes of the captured references.

ClosureType::operator ret(*)(params)

typedef ret(*F)(params);
operator F() const;

This member function is only defined if the capture list of the lambda-expression is empty.

The value returned by this conversion function is a function pointer that, when invoked, has the same effect as invoking the closure object's function call operator directly.

ClosureType::ClosureType()

ClosureType() = delete;
ClosureType(const ClosureType& ) = default;
ClosureType(ClosureType&& ) = default;

Closure types are not DefaultConstructible. The copy constructor and the move constructor are implicitly-declared and may be implicitly-defined according to the usual rules for implicit copy constructors and move constructors.

ClosureType::operator=()

ClosureType& operator=(const ClosureType&) = delete;

Closure types are not CopyAssignable.

ClosureType::~ClosureType()

~ClosureType() = default;

The destructor is implicitly-declared.

ClosureType::CapturedParam

T1 a;

T2 b;

...

If the lambda-expression captures anything by copy (either implicitly with capture clause [=] or explicitly with a capture that does not include the character &, e.g. [a, b, c]), the closure type includes unnamed non-static data members, declared in unspecified order, that hold copies of all entities that were so captured.

The type of each data member is the type of the corresponding captured entity, except if the entity has reference type (in that case, references to functions are captured as-is, and references to objects are captured as copies of the referenced objects).

For the entities that are captured by reference (with the default capture [&] or when using the character &, e.g. [&a, &b, &c]), it is unspecified if additional data members are declared in the closure type.

[edit] Example

This example shows (a) how to pass a lambda to a generic algorithm and (b) how objects resulting from a lambda declaration can be stored in std::function objects.

#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
 
int main()
{
    std::vector<int> c { 1,2,3,4,5,6,7 };
    int x = 5;
    c.erase(std::remove_if(c.begin(), c.end(), [x](int n) { return n < x; } ), c.end());
 
    std::cout << "c: ";
    for (auto i: c) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
 
    // the type of a closure cannot be named, but can be inferred with auto
    auto func1 = [](int i) { return i+4; };
    std::cout << "func1: " << func1(6) << '\n'; 
 
    // like all callable objects, closures can be captured in std::function
    // (this may incur unnecessary overhead)
    std::function<int(int)> func2 = [](int i) { return i+4; };
    std::cout << "func2: " << func2(6) << '\n'; 
}

Output:

c: 5 6 7
func1: 10
func2: 10

[edit] See also

auto specifier specifies a type defined by an expression (C++11)
(C++11)
wraps callable object of any type with specified function call signature
(class template)