Consider the example:
#include <iostream>
#include <functional> // std::function
#include <vector> // std::vector
#include <algorithm> // std::for_each
int main(){
auto adder = [](int x) {
return [&](int y) {
return x+=y;
};
};
std::vector < std::function<int(int)> > vec;
vec.push_back(adder(1));
vec.push_back(adder(10));
std::for_each(vec.begin(), vec.end(), [](std::function<int(int)> f){std::cout << f(33) << " ";});
std::cout << std::endl;
}
One expects the integers 34 and 43 43 and 76, but instead gcc 4.6.0 produces "internal compiler error: Segmentation fault". What is wrong with the code?
Edit: Several other examples are discussed here.
(Edit: this certainly does not explain the ICE; I read the original question too hastily.)
The One problem in that code is that the lambdas returned from the adder
function contain dangling references to the x
variable that no longer exists. Capture by copy ([=]
or [i]
) instead of a reference ([&]
) and everything should work.
It seems, that in your example trailing-return-type cannot be omitted. Here is excerpt from standard (5.1.2 Lambda expressions):
If a lambda-expression does not
include a trailing-return-type, it is
as if the trailing-return-type denotes
the following type: — if the compound-statement is of the form { attribute-specifier-seq return expression ; } the type of the returned expression after lvalue-to-rvalue conversion (4.1), array-to-pointer conversion (4.2), and function-to-pointer conversion (4.3); — otherwise, void.
Returned value in your example cannot be used for conversions mentioned above. Following code with explicitely added return type compiles in VS 2010:
auto adder = [] (int x) -> std::function<int (int)> {
return [=]( int y ) {
return x + y;
};
};
You're just completely missing the point. The need for std::function
is very, very obvious.
- All lambdas have a unique type at compile-time
- You want the vector to hold any functional object at run-time.
- Therefore, some sort of type erasure is required, which is the job
std::function
does.
How on earth could you ever create a vector that varies at run-time a compile-time fact, like the type contained within it? That's just logically impossible- unless you use an abstraction such as std::function
.
Of course, if you only ever want one lambda type within, then you don't need std::function
at all. This is relatively rare though.
int main() {
auto adder = [](int x) {
return [=](int y) {
return x + y;
};
};
// alternatively- you MUST copy the argument as it will cease to exist
// but once it's in the lambda, you can use "mutable" to allow you to
// modify the copy that each lambda has.
/*
auto adder = [](int x) {
return [=](int y) mutable {
return x += y;
};
};
*/
std::vector<decltype(adder(0))> adders;
adders.emplace_back(adder(0));
adders.emplace_back(adder(1));
std::for_each(adders.begin(), adders.end(), [](decltype(*adders.begin())& ref) {
std::cout << ref(33);
});
std::cin.get();
}
MSVC won't actually compile this little snippet, but I think that's a bug and judging by the reports of your compiler, I expect that it will compile there and indeed work correctly.