Super short explanation of the problem/question
A lambda expression that captures a variable, and is passed to a function as a functor thing. My confusion is in that the lambda modifies a variable that it captured... but it was captured in a completely different scope, if at all.
Preface
This isn't a problem, but more of a question on what's going on with the code, internally and compilator-ly. As in the title and the tags, it's about lambdas, capturing, functors, and templates. I am myself a very beginner programmer and english is not my first language, so my excuses if something isn't very clear. Preferably also, the very liberal use of autos might not be in the "scope" of the question; but rather lambdas and functors and templates. I've also searched the internet, but either I'm searching wrong or this is some very obscure/obfuscated use of lambdas and stuff.
Explanation of the code and the problem
- I have a templated function
riddle()
that gets two parameters/types:functor
andsomething
. In the body of the function, there's a simplefor
loop the loops from 0 to 6 and passes these numbers tofunctor
, along withsomething
. - In
main()
there's a vectorvec
that gets created. This will be important later. - The function
riddle()
gets called with two lambdas. First being one that captures by reference and gets twoauto
variables. It also returns anauto
, and (!!!) pushes back the firstauto
variable to thatvec
. - The second lambda that
riddle()
gets is one that returns anauto
. - The contents of
vec
show numbers from 0 to 6.
(The explanation of the problem(s) are after the code.)
The minimal reproducible example
template <typename ftype, typename stype>
auto riddle(ftype functor, stype something) {
for (int i = 0; i <= 6; i++) {
functor(i, something);
};
};
int main() {
std::vector<int> vec;
riddle(
[&](auto o, auto p)->auto { vec.push_back(o); }, // functor
[]()->auto {return; } // something
);
for (auto i : vec) { std::cout << "\n " << i; }; // prints numbers 0 to 6
std::cin >> vec[0]; // just so it shows the results before a return
return 0;
};
This code works on C++14 and up, and was tested in MS Visual Studio 2017 and in CodeBlocks 17.12, and also both on release and debug configurations.
The first problem/question
The last bullet point is the part that confuses me. I was explained that a lambda that captures can only get the variables that are in the scope that the lambda was called. In this case, a lambda/functor gets called in an entirely different scope and function, but somehow still modifies the vector that it captured where it was written. I tried it out, and it still works like this when passed deeper down another function, around as a pointer, or even to another thread.
The questions are: What does the compiler do here, actually? Does it create a (lambda?) object that holds a reference/pointer to that vector? Would this kind of thing be easy to do without lambdas like that? Is that brutally inefficient, or does the compiler optimize it somehow? Shouldn't that lambda be "transformed" or "inlined" by the compiler, making it unable to see that vector?
The second problem/question
This, albeit a less important question, is what actually happens with the second lambda and the something
in the riddle()
function. What is its type? Is it void? A nullptr? A function/functor?