#cpp
Следующий код, скомпилированный в VS2015, вызывает конструктор копирования Foo при
захвате foo:
void bar(Foo& foo) {
auto f = [foo]() {
};
}
Ранее, ошибочно полагал, что внутри лямбды, foo должна была остаться ссылкой, по
аналогии с обычными функциями:
template void f(T foo) {
// здесь доступен исходный объект foo, который был создан при вызове baz(Foo());
// в случае, если это была бы лямбда с захватом foo по значению, здесь получается
копия
}
void bar(const Foo& foo) {
f(foo);
}
baz(Foo());
Не разобрался в спецификации до конца, правильно ли понял, что при захвате по значению
будет создана константная переменная (с помощью конструктора копирования), доступная
внутри лямбды, имеющая тип Foo, не зависимо от того является внешняя переменная ссылкой
на Foo или экземпляром Foo.
update
Что интересно, если вызывать не f(foo); а просто f(foo) (второй пример
кода), то шаблон инстанцируется типом Foo, а не Foo&. Т.е. при автоматическом выборе
типа компилятор не различает ссылка это или экземпляр.
Ответы
Ответ 1
Чтобы разобрать Ваш пример, нужно обратиться к стандарту и понимать, что для реализации лямбда-функций компилятор создаёт тип-замыкание. Так вот, когда в списке захвата, некий объект закхватывается по значению, тогда в замыкании создаётся объект такого же типа, какой имеет этот объект, если это не ссылка. Если же это ссылка, то типом в замыкании будет тип, на который эта ссылка ссылается. Стандарт [expr.prim.lambda]p15: An entity is captured by copy if it is implicitly captured and the capture-default is = or if it is explicitly captured with a capture that is not of the form & identifier or & identifier initializer. For each entity captured by copy, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified. The type of such a data member is the type of the corresponding captured entity if the entity is not a reference to an object, or the referenced type otherwise. [ Note: If the captured entity is a reference to a function, the corresponding data member is also a reference to a function. — end note ] A member of an anonymous union shall not be captured by copy Таким образом, в замыкании Ваш foo будет иметь тип Foo.Ответ 2
Да, вы поняли верно. Вы захватываете foo по значению, так что в лямбде создается копия значения foo по данной ссылке. Если захватите как [&foo], то это будет захват по ссылке, т.е. в лямбде будет обычная ссылка. Update О типах. void bar(int& foo) { cout << typeid(foo).name() << endl; auto f = [foo]() { cout << typeid(foo).name() << endl; }; f(); } Этот код утверждает, что foo в обоих случаях имеет тип int. Если воспользоваться методом Мейерса, то код void bar(int& foo) { TDfoo1Type; cout << typeid(foo).name() << endl; auto f = [foo]() { TD foo2Type; cout << typeid(foo).name() << endl; }; f(); auto g = [&foo]() { TD foo3Type; cout << typeid(foo).name() << endl; }; g(); } дает сообщения об ошибках с типами int&, int и int&. Так что, скорее всего, foo при передаче по значению хранится как int. Впрочем, чего т следовало ожидать.
Комментариев нет:
Отправить комментарий