2

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 and something. In the body of the function, there's a simple for loop the loops from 0 to 6 and passes these numbers to functor, along with something.
  • In main() there's a vector vec 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 two auto variables. It also returns an auto, and (!!!) pushes back the first auto variable to that vec.
  • The second lambda that riddle() gets is one that returns an auto.
  • 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?

Community
  • 1
  • 1
Dreamykass
  • 21
  • 1
  • *I was explained that a lambda that captures can only get the variables that are in the scope that the lambda was called* That seems to be your issue. Lambda's capture when they are declared, not called. – NathanOliver May 20 '19 at 19:34
  • There's still questions of what the compiler actually does there. That a lambda simply captures the vector, I can see myself :( As I wrote in the second to last paragraph: "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?" – Dreamykass May 20 '19 at 19:39
  • 2
    Did you read [the dupe target](https://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11)? – NathanOliver May 20 '19 at 19:41
  • 2
    Also [the reference](https://en.cppreference.com/w/cpp/language/lambda) does a really good job. – NathanOliver May 20 '19 at 19:41
  • Compiler does very simple thing - it creates a class which has as many members as variables lambda captures. For every variable, if captured by reference, member type is a reference, if by value, member type is a value. It than initializes those members from capture arguments. Than it behaves exactly like such class written by hand would behave. – SergeyA May 20 '19 at 19:45
  • Alright, I think I get it now. Thanks, both of ya! (Should I mark it as accepted/solved or something? Or just leave it as is?) – Dreamykass May 20 '19 at 19:50
  • @Dreamykass _"Should I mark it as accepted/solved or something?"_ No, there's no further action needed unless you disagree with the duplicates answers to solve your question. In that case [edit] your question and give a detailed explanation why not. – πάντα ῥεῖ May 20 '19 at 19:54
  • Alright then, thanks! – Dreamykass May 20 '19 at 19:56

0 Answers0