3

Exactly where is the machine code for a lambda stored, if the lambda takes an argument of auto type?

Details follow.

Lambdas are compiled at compile time, are they not? As far as I know, compilation requires that types be known at compile time.

But if so, then how is this MCVE possible?

#include <typeinfo>
#include <iostream>

namespace My {
    struct S {};
}

int main()
{
    auto n = 42;
    // An object n exists on the stack.
    auto f = [](const auto n) {return n;};
    // The f resembles a template. Does an object f exist on the stack?
    const std::type_info& ti1 {typeid(f)};
    const std::type_info& ti2 {typeid(f(My::S {}))};
    std::cout
      << &n         << " "
      << n          << " "
      << &f         << " " // If f is no object then why does this work?
      << ti1.name() << " "
      << ti2.name() << "\n";
    return 0;
}

Output (demangled): 0x7ffd6a22b41c 42 0x7ffd6a22b41b main::{lambda(auto:1)#1} My::S

Does this imply that no object f, except perhaps for a placeholder, exists on the stack? But if so, then f is not an object but merely a template, is it not?

I am confused. If you can, please explain what kind of compile-time/run-time object a lambda like f is, how the compiler treats it, where it exists at run time, roughly how it could be laid out on the stack, and so on. Even a partial answer would be appreciated.

(I observe, incidentally, based on addresses output, that f—or the placeholder for f—seems to occupy exactly one byte at run time, but do not know what sense to make of this observation. Note that a C++14 or later compiler is required, for C++11 cannot handle such template-like lambdas.)

Related:

thb
  • 13,796
  • 3
  • 40
  • 68
  • @Barry Thank you for the link. I have edited the question to clarify why it does not duplicate the question linked. My MCVE does not compile in C++11. The C++11 lambda makes sense to me; it is the C++14 lambda that confuses. Note the lambda's `auto` parameter. – thb Mar 17 '19 at 21:49
  • 3
    A lambda is essentially an instance of a class with overloaded `operator()`. If the lambda is a template (e.g. with an `auto` parameter) then said `operator()` is a template, otherwise it's not a template. *"f seems to occupy exactly one byte at run time"* Since its capture list is empty (`[]`), your lambda has no "member variables" and behaves like any other class with no member variables. Objects in C++ can't have size `0`, so it occupies `1` byte (in which nothing is stored). – HolyBlackCat Mar 17 '19 at 22:04
  • @HolyBlackCat That makes sense. Thus, the templatized `operator()` would be instantiated not in the context in which it is defined but rather in the context in which it is called. I suppose that this probably restricts the way the lambda object itself can be handled in some way, but this is complicated. I'll think on it, based on your advice. The comment is appreciated. – thb Mar 17 '19 at 22:11
  • @HolyBlackCat The representation consists of captures! I had not known that. – thb Mar 17 '19 at 22:14
  • 1
    for exposition, equivalent c++11 code: http://coliru.stacked-crooked.com/a/8261a611da6b51fe – Richard Hodges Mar 17 '19 at 22:20
  • @RichardHodges Aha. After five or ten minutes of study, your equivalent makes perfect sense to me. Clearer. So even if the one-byte lambda object were passed out of `main()` to different nontemplate function, that other function could not *call* the lambda. Reason: at compile time, the member template had been out of scope. – thb Mar 17 '19 at 22:33
  • @RichardHodges If the question were not closed, yours would be a fine *answer.* (Since Barry is not a participant in this comment thread, the system has probably not notified him at all of the thread. Too bad. He might reopen if he saw.) – thb Mar 17 '19 at 22:34
  • The only difference is that you're using a generic lambda (new C++14 feature), but the bulk of your question is really about what a lambda _actually is_. – Barry Mar 17 '19 at 23:00
  • 1
    @Barry This isn't a duplicate, OP is asking how the code is compiled and where it is stored, rather than what it does. Please re-open. – Mikhail Mar 17 '19 at 23:07
  • @Barry Thank you for sparing the time to take a closer look. Your time was not wasted, for the question (edited) is clearer now. (I had not understood why it looked like a duplicate; greater clarity was needed by me.) – thb Mar 17 '19 at 23:20
  • @RichardHodges The question has been reopened. When you have some time, would you care to post your comment as an *answer?* Your comment nailed it. – thb Mar 17 '19 at 23:22
  • 1
    @thd: Does this question cover yours (and RichardHodges's answer) sufficiently? https://stackoverflow.com/q/17233547/103167 – Ben Voigt Mar 18 '19 at 00:23
  • @BenVoigt After closing and reopening the question, it would be ironic to close it again. However, yes, I believe that the question you link probably does cover sufficiently. Moreover, the linked questioner was less confused than I when he asked the question, so his question is clearer than mine. – thb Mar 18 '19 at 00:36
  • I should not insult the original closer by voting myself to reclose the question, because, you know ... open, close, open, close; I have exercised him enough. However, if you now close the question no one will object. Thanks for the link. If no one else has learned anything useful about C++14 lambdas today, why, I certainly have. Most educational. – thb Mar 18 '19 at 00:41
  • Most of the job of a duplicate-closer is finding the right question to link to. Anyone casting a close-as-dupe vote (and especially gold badge holder who can close with one vote) should be open to having the question re-closed with a different duplicate. Although recently they added the ability to edit the list of linked questions, so close-reopen-close is no longer always necessary. – Ben Voigt Mar 18 '19 at 00:44

0 Answers0