С++ 11 лямбда-захват по значениям в точке объявления
Нижеприведенный код печатает 0, но я ожидаю увидеть 1. Мой вывод состоит в том, что функции лямбда не вызывают, фактически передавая захваченные параметры в функции, что более интуитивно. Я прав, или я чего-то не хватает?
#include <iostream>
int main(int argc, char **argv){
int value = 0;
auto incr_value = [&value]() { value++; };
auto print_value = [ value]() { std::cout << value << std::endl; };
incr_value();
print_value();
return 0;
}
Ответы
Ответ 1
Лямбда-функции -, вызываемые фактической передачей захваченных параметров функции.
value
равно 0 в точке, где определяется лямбда (и value
). Поскольку вы захватываете по значению, не имеет значения, что вы делаете с value
после захвата.
Если вы взяли value
по ссылке, то вы увидите 1 напечатанную, так как хотя точка захвата остается неизменной (определение лямбда), вы будете печатать текущее значение захваченного объекта, а не его копия была создана при ее захвате.
Ответ 2
Да, захваты выполняются в точке, обозначенной лямбдой, а не при ее вызове. Подумайте о лямбде как объекте функции, конструктор которого принимает захваченные переменные в качестве параметров и присваивает их соответствующим переменным-членам (значения или ссылки в зависимости от режима захвата). Фактический вызов лямбды не имеет магии, это просто регулярный вызов operator()
основного объекта функции.
Захват вещей в точке вызова не имеет большого смысла - что было бы захвачено, если лямбда была возвращена или передана как параметр другой функции и называется там? На самом деле существуют языки, которые ведут себя таким образом - если вы ссылаетесь на переменную x
в функции, предполагается, что она относится к любой переменной с именем x
, находящейся в настоящее время в области в точке вызова. Это называется динамическим охватом. Альтернатива, используемая большинством языков, потому что упрощает рассуждение о программах, называется лексическим охватом.
http://en.wikipedia.org/wiki/Lexical_scoping#Lexical_scoping_and_dynamic_scoping
Ответ 3
Проблема заключается в том, что ваша функция печати захватывается по значению, а не по ссылке.
#include <iostream>
int main(int argc, char **argv){
int value = 0;
auto incr_value = [&value]() { value++; };
auto print_value = [ value]() { std::cout << value << std::endl; };
auto print_valueref = [ &value]() { std::cout << value << std::endl; };
incr_value();
print_value();
print_valueref();
return 0;
}
Вывод 0 и 1, как ожидалось. Первый захвачен значением и печатает значение в точке захвата; второй фиксирует ссылку, а затем печатает ее значение.