您的位置:首页 > 编程语言 > C语言/C++

Anonymous function in C++

2016-04-19 16:11 302 查看

C++ (since C++11)

C++11 provides support for anonymous functions, calledlambda expressions. A lambda expression has the form:

[capture](parameters) -> return_type { function_body }


An example lambda function is defined as follows:

[](int x, int y) -> int { return x + y; }


C++11 also supports
closures. Closures are defined between square brackets
[
and
]
in the declaration of lambda expression. The mechanism allows these variables to be captured by value or by reference. The following table demonstrates this:

[]        //no variables defined. Attempting to use any external variables in the lambda is an error.
[x, &y]   //x is captured by value, y is captured by reference
[&]       //any external variable is implicitly captured by reference if used
[=]       //any external variable is implicitly captured by value if used
[&, x]    //x is explicitly captured by value. Other variables will be captured by reference
[=, &z]   //z is explicitly captured by reference. Other variables will be captured by value


Variables captured by value are constant by default. Adding
mutable
after the parameter list makes them non-constant.

The following two examples demonstrate usage of a lambda expression:

std::vector<int> some_list{ 1, 2, 3, 4, 5 };
int total = 0;
std::for_each(begin(some_list), end(some_list), [&total](int x) {
total += x;
});


This computes the total of all elements in the list. The variable
total
is stored as a part of the lambda function's closure. Since it is a reference to the stack variable
total
, it can change its value.

std::vector<int> some_list{ 1, 2, 3, 4, 5 };
int total = 0;
int value = 5;
std::for_each(begin(some_list), end(some_list), [&, value, this](int x) {
total += x * value * this->some_func();
});


This will cause
total
to be stored as a reference, but
value
will be stored as a copy.

The capture of
this
is special. It can only be captured by value, not by reference.
this
can only be captured if the closest enclosing function is a non-static member function. The lambda will have the same access as the member that
created it, in terms of protected/private members.

If
this
is captured, either explicitly or implicitly, then the scope of the enclosed class members is also tested. Accessing members of
this
does not require explicit use of
this->
syntax.

The specific internal implementation can vary, but the expectation is that a lambda function that captures everything by reference will store the actual stack pointer of the function it is created in, rather than individual references to stack variables.
However, because most lambda functions are small and local in scope, they are likely candidates forinlining, and thus will not need any additional
storage for references.

If a closure object containing references to local variables is invoked after the innermost block scope of its creation, the behaviour isundefined.

Lambda functions are function objects of an implementation-dependent type; this type's name is only available to the compiler. If the user wishes to take a lambda function as a parameter, the type must be a template type, or they must create a
std::function

or a similar object to capture the lambda value. The use of the
auto
keyword can help store the lambda function,

auto my_lambda_func = [&](int x) { /*...*/ };
auto my_onheap_lambda_func = new auto([=](int x) { /*...*/ });


Here is an example of storing anonymous functions in variables, vectors, and arrays; and passing them as named parameters:

#include <functional>
#include <vector>
#include <iostream>

double eval(std::function <double(double)> f, double x = 2.0)
{
return f(x);
}

int main()
{
std::function<double(double)> f0    = [](double x){return 1;};
auto                          f1    = [](double x){return x;};
decltype(f0)                  fa[3] = {f0,f1,[](double x){return x*x;}};
std::vector<decltype(f0)>     fv    = {f0,f1};
fv.push_back                  ([](double x){return x*x;});
for(int i=0;i<fv.size();i++)
std::cout << fv[i](2.0) << std::endl;
for(int i=0;i<3;i++)
std::cout << fa[i](2.0) << std::endl;
for(auto &f : fv)
std::cout << f(2.0) << std::endl;
for(auto &f : fa)
std::cout << f(2.0) << std::endl;
std::cout << eval(f0) << std::endl;
std::cout << eval(f1) << std::endl;
std::cout << eval([](double x){return x*x;}) << std::endl;
return 0;
}


A lambda expression with an empty capture specification (
[]
) can be implicitly converted into a function pointer with the same type as the lambda was declared with. So this is legal:

auto a_lambda_func = [](int x) { /*...*/ };
void (* func_ptr)(int) = a_lambda_func;
func_ptr(4); //calls the lambda.


The
Boost library provides its own syntax for lambda functions as well, using the following syntax:[11]

for_each(a.begin(), a.end(), std::cout << _1 << ' ');
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: