The following code, compiled in VS2015, calls the Foo copy constructor when foo captured:

 void bar(Foo& foo) { auto f = [foo]() { }; } 

Previously, mistakenly believed that inside lambda, foo should have remained a reference, by analogy with the usual functions:

 template<typename T> void f(T foo) { // здесь доступен исходный объект foo, который был создан при вызове baz(Foo()); // в случае, если это была бы лямбда с захватом foo по значению, здесь получается копия } void bar(const Foo& foo) { f<const Foo&>(foo); } baz(Foo()); 

I didn’t understand the specification, did I understand correctly that when capturing by value, a constant variable would be created (using the copy constructor), available inside the lambda, of type Foo , regardless of whether the external variable is a reference to Foo or an instance of Foo .

update

What is interesting, if you call not f<const Foo&>(foo); but just f(foo) (second code example), then the template is instantiated with the type Foo , not Foo& . Those. With automatic type selection, the compiler does not distinguish between a reference or an instance.

    2 answers 2

    To disassemble your example, you need to refer to the standard and understand that to implement lambda functions, the compiler creates a type-closure. So, when in the capture list, an object is captured by value, then an object of the same type as this object is created in the closure, if it is not a link. If it is a link, then the type in the closure will be the type to which the link refers.

    Standard [expr.prim.lambda] p15:

    It is not a form and identifier or an identifier initializer. For each entity, it’s not a static data member. The order of these members is unspecified. It is not a reference. It is a reference to a function. - end note]

    Thus, in the closure, your foo will be of type Foo .

    • For simple types (int &, boolean & instead of foo &), we can expect the same behavior? - Vladimir Gamalyan
    • @VladimirGamalian, it does not depend on the types, so - yes - ixSci

    Yes, you get it right. You capture foo by value , so a copy of the value of foo is created in the lambda over this link.

    If you capture as [&foo] , then it will be capture by reference, i.e. in lambda there will be a normal link.

    Update About Types.

     void bar(int& foo) { cout << typeid(foo).name() << endl; auto f = [foo]() { cout << typeid(foo).name() << endl; }; f(); } 

    This code states that foo is of type int in both cases.

    If you use the method of Meyers, the code

     void bar(int& foo) { TD<decltype(foo)> foo1Type; cout << typeid(foo).name() << endl; auto f = [foo]() { TD<decltype(foo)> foo2Type; cout << typeid(foo).name() << endl; }; f(); auto g = [&foo]() { TD<decltype(foo)> foo3Type; cout << typeid(foo).name() << endl; }; g(); } 

    gives error messages with types int& , int and int& . So, most likely, foo when passed by value is stored as an int . However, what was to be expected.

    • Those. wrong to assume that when capturing by value the type of the variable does not change? - Vladimir Gamalyan
    • @VladimirGamalian: I would say that the type does not change, but without & not the original is captured, but a copy of the variable. But you need to experiment. - VladD
    • one
      Are not the types of Foo and Foo& different? - Vladimir Gamalyan
    • Well, for example, you are not surprised that the rvalue when passing to the function becomes lvalue? This is also a change of type ... On the other hand, with these links, now the devil himself will break his leg ... It would be necessary to read Meyers to answer you exactly. - Harry
    • one
      By the way, if decltype(foo) inside a lambda, then it will give type foo from the outside, not inside it, since This is not odr-use. On the other hand, decltype((foo)) will give the type that foo would have had if it were captured into a closure - ixSci