-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathlambda.yo
More file actions
94 lines (86 loc) · 4.24 KB
/
lambda.yo
File metadata and controls
94 lines (86 loc) · 4.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
em(Generic lambda expressions) hi(lambda: generic) use tt(auto) to define their
parameters. When used, an appropriate lambda expression is created by looking
at the actual types of arguments. Since they are generic, they can be used
inside one function with different types of arguments. Here is an example
(assuming all required headers and namespace declaration):
verbinclude(-ns4 //code examples/genlambda.cc)
The generic lambda function is defined in lines 3 through 6, and is
assigned to the tt(lambda) identifier. Then, tt(lambda) is passed to
tt(accumulate) in lines 12 and 13. In line 12 it is instantiated to add
tt(int) values, in line 13 to add tt(std::string) values: the same tt(lambda)
is instantiated to two completely different functors, which are only locally
available in tt(main).
Generic lambda expressions are equivalent to class templates. To illustrate:
the above example of a generic lambda expression could also be implemented
using the following class template:
verb(
struct Lambda
{
template <typename LHS, typename RHS>
auto operator()(LHS const &lhs, RHS const &rhs) const
{
return lhs + rhs;
}
};
auto lambda = Lambda{};
)
This identity implies that using tt(auto) in the lambda expression's
parameter list obeys the rules of template argument deduction (cf. section
ref(TEMPFUNARGS)), which are somewhat different from the way tt(auto) normally
operates.
Another extension is how generic lambda expressions capture outer scope
variables. Previously variables could only be captured by value or by
reference. As a consequence an outer scope variable of a type that only
supports move construction could not be passed by value to a lambda
function. This restriction was dropped, allowing variables to be initialized
from arbitrary expressions. This not only allows move-initialization of
variables in the lambda introducer, but variables may also be initialized if
they do not have a correspondingly named variable in the lambda expression's
outer scope. In this case initializer expressions can be used as shown in this
example:
verb(
auto fun = [value = 1]
{
return value;
};
)
This lambda function (of course) returns 1: the declared capture deduces
the type from the initializer expression as if tt(auto) had been used.
To use move-initialization tt(std::move) should be used. E.g., a
em(unique_ptr) only supports move-assignment. Here it is used to return one of
its values via a lambda function:
verb(
std::unique_ptr<int> ptr(new int(10));
auto fun = [value = std::move(ptr)]
{
return *value;
};
)
In generic lambda expressions the keyword tt(auto) indicates that the compiler
determines which types to use when the lambda function is instantiated. A
generic lambda expression therefore em(is) a class template, even though it
doesn't look like one. As an example, the following lambda expression defines
a generic class template, which can be used as shown:
verb(
char const *target = "hello";
auto lambda =
[target](auto const &str)
{
return str == target;
};
vector<string> vs{stringVectorFactory()};
find_if(vs.begin(), vs.end(), lambda);
)
This works fine, but if you define tt(lambda) this way then you should be
prepared for complex error messages if the types of the derefenced iterators
and lambda's (silently assumed) tt(str) type don't match.
Here is a little program illustrating how generic lambda expressions can be
used in other generic lambda expressions: class templates could also have been
used. In lines 1 through 9 a generic lambda expression tt(accumulate) is
defined, defining a second paramater which is used as a function: its argument
therefore should be usable as a function. A functor definitely is, an the
second generic lambda expression tt(lambda), defined in lines 11 through 14
provides it. In line 21 tt(accumulate) and tt(lambda) are instantiated so that
they operate on (a vector of) tt(ints), in line 22 they are instantiated for
processing (a vector of) tt(strings):
verbinsert(-ns4 //code examples/genlambda2.cc)