Consider the following snippet:
#include <iostream> #include <vector> #include <functional> int main() { std::vector<int>v = {0,1,2,3,4,5,6}; std::function<const int&(int)> f = [&v](int i) { return v[i];}; std::function<const int&(int)> g = [&v](int i) -> const int& { return v[i];}; std::cout << f(3) << ' ' << g(3) << std::endl; return 0; }
I was expecting the same result: in f
, v
is passed by const reference, so v[i]
should have const int&
type.
However, I get the result
0 3
If I do not use std::function, everything is fine:
#include <iostream> #include <vector> #include <functional> int main() { std::vector<int>v = {0,1,2,3,4,5,6}; auto f = [&v](int i) { return v[i];}; auto g = [&v](int i) -> const int& { return v[i];}; std::cout << f(3) << ' ' << g(3) << std::endl; return 0; }
output:
3 3
Thus I'm wondering:
In the second snippet, what is the return type of the lambda expression f
? Is f
the same as g
?
In the first snippet, what happened when the std::function f
was constructed, causing the error?
The return type for a lambda is specified using a C++ feature named 'trailing return type'. This specification is optional. Without the trailing return type, the return type of the underlying function is effectively 'auto', and it is deduced from the type of the expressions in the body's return statements.
The characteristics of lambda functions are: You can use them as an anonymous function inside other functions. The lambda functions do not need a return statement, they always return a single expression.
The [=] you're referring to is part of the capture list for the lambda expression. This tells C++ that the code inside the lambda expression is initialized so that the lambda gets a copy of all the local variables it uses when it's created.
The type of a lambda expression is unspecified. But they are generally mere syntactic sugar for functors. A lambda is translated directly into a functor.
The return type of a lambda uses the auto
return type deduction rules, which strips the referenceness. (Originally it used a slightly different set of rules based on lvalue-to-rvalue conversion (which also removed the reference), but that was changed by a DR.)
Hence, [&v](int i) { return v[i];};
returns int
. As a result, in std::function<const int&(int)> f = [&v](int i) { return v[i];};
, calling f()
returns a dangling reference. Binding a reference to a temporary extends the lifetime of the temporary, but in this case the binding happened deep inside std::function
's machinery, so by the time f()
returns, the temporary is gone already.
g(3)
is fine because the const int &
returned is bound directly to the vector element v[i]
, so the reference is never dangling.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With