20

As I know all data types must be known at compile time, and lambda is not a type. Does lambda got translated into anonymous struct with operator() or std::function wrapped?

For example,

std::for_each(v.begin(), v.end(), [](int n&){n++;});
Barry
  • 286,269
  • 29
  • 621
  • 977
SwiftMango
  • 15,092
  • 13
  • 71
  • 136
  • 2
    `std::function` has no language connections like `std::initializer_list` does. – chris Nov 09 '14 at 23:46
  • It stems from my lack of knowledge. Purely random. – SwiftMango Nov 09 '14 at 23:49
  • 2
    Lambda type is [unspecified](http://stackoverflow.com/questions/7951377/what-is-the-type-of-lambda-when-deduced-with-auto-in-c11). – Marcin Nov 09 '14 at 23:49
  • I just want to point out that the type of a lambda, albeit unspecified and non-expressible, *can* be deduced by templates. And *that*, I think, is powerful. – Quentin Nov 09 '14 at 23:56

3 Answers3

15

A variation of the as-if rule, the C++11 standard says:

§5.1.2/3 [..] An implementation may define the closure type differently from what is described below provided this does not alter the observable behavior of the program other than by changing:

— the size and/or alignment of the closure type,

— whether the closure type is trivially copyable (Clause 9),

— whether the closure type is a standard-layout class (Clause 9), or

— whether the closure type is a POD class (Clause 9).

I believe this is what people mean when they say that it's unspecified. However what's guaranteed as already stated in the other answers is the following:

Original author: Lightness Races in Orbit

[C++11: 5.1.2/3]: The type of the lambda-expression (which is also the type of the closure object) is a unique, unnamed non-union class type — called the closure type — whose properties are described below. This class type is not an aggregate (8.5.1). The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding lambda-expression. [..]

The clause goes on to list varying properties of this type. Here are some highlights:

[C++11: 5.1.2/5]: The closure type for a lambda-expression has a public inline function call operator (13.5.4) whose parameters and return type are described by the lambda-expression’s parameter-declaration-clause and trailing-return-type respectively. [..]

[C++11: 5.1.2/6]: The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

Community
  • 1
  • 1
13

From the standard §5.1.2.3:

The type of the lambda-expression... is a unique, unnamed non-union class type

It is its own type. Every time. So for instance:

auto a = []{ return 1; };
auto b = []{ return 1; };

a and b will necessarily have different types. They are both convertible to std::function<int()>, but not to each other:

std::function<int()> c = a; // OK
a = b; // NOPE

Adding a few more examples to add some clarity:

decltype(a) a2 = a; // OK, explicitly specifying the correct type

template <typename F>
void foo(F f) { ... }

foo(a); // calls foo<decltype(a)>, not foo<std::function<int()>
Barry
  • 286,269
  • 29
  • 621
  • 977
  • This does not answer my question. I know lambda does not have a type (as I stated in the question). My question is how they are compiled since they don't have type. – SwiftMango Nov 09 '14 at 23:55
  • 5
    @texasbruce You misunderstand. They *do* have a type. It's just *unique* and *unnamed*. In my example, you can do `using T = decltype(a); T a2 = a;` That will compile just fine. – Barry Nov 09 '14 at 23:56
  • @texasbruce: The answer says that the type of a lambda expression is a unique, unnamed non-union class type. That's a different statement from "does not have a type". A lambda *does* have a type, but the type does not have a name. – rici Nov 09 '14 at 23:57
  • @Barry, I believe `using T = decltype(a)` is actually illegal. http://stackoverflow.com/questions/4846540/c11-lambda-in-decltype – sfjac Nov 10 '14 at 00:05
  • 1
    @sfjac He's using `decltype` on an expression instead of the resulting object. Once we have `a`, it's just an object like any other. Example: http://ideone.com/V7lXdg – Barry Nov 10 '14 at 00:07
6

A lambda expression constructs an unnamed type, with each one having a different type. They are not std::function implementations. More info is provided here: What is a lambda expression in C++11? and here: How to convert a lambda to an std::function using templates

You can unveil the type on your specific compiler with a trick like this:

void foo(int);

int main() {
    auto a = []{ return 1; };
    auto b = []{ return 1; };

    foo(a);

    foo(b);

    return 0;
}

Compiling with clang on my mac gives:

/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:11:5: error: no matching function for call to 'foo'
    foo(a);
    ^~~
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from 
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:8:14>' to 'int' for 1st argument
void foo(int);
     ^
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:13:5: error: no matching function for call to 'foo'
    foo(b);
    ^~~
/Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:5:6: note: candidate function not viable: no known conversion from 
'<lambda at /Users/jcrotinger/ClionProjects/so_lambda_type/main.cpp:9:14>' to 'int' for 1st argument
void foo(int);

@Barry points out that you can use typeid instead. If I print out typeid(a).name() and typeid(b).name() on my system, I get:

Z4mainE3$_0
Z4mainE3$_1

which demangle to

main::$_0
main::$_1

Just wanted to include this for completeness. I actually find the error message version a little more informative. :)

Community
  • 1
  • 1
sfjac
  • 7,119
  • 5
  • 45
  • 69
  • So it is anonymous struct? – SwiftMango Nov 09 '14 at 23:54
  • As per @texasbruce's elaborations, they have a type, but it is an implementation detail. – sfjac Nov 09 '14 at 23:57
  • 1
    @sfjac If you really want to look at the type, you can just use `typeid()` and pass it through a [demangler](http://stackoverflow.com/questions/281818/unmangling-the-result-of-stdtype-infoname) – Barry Nov 10 '14 at 00:09
  • @Barry A demangler is unlikely to be necessary, when one is already provided with the gcc toolchain. [c++filt](https://sourceware.org/binutils/docs/binutils/c_002b_002bfilt.html) –  Nov 10 '14 at 00:14
  • @remyabel sure, but maybe you want to write a function that prints types during code runtime? `c++filt` is great for checking out symbol files though. – Barry Nov 10 '14 at 00:18