Передача лямбды в функцию по ссылке
Есть вот такой пример:
#include <iostream>
#include <functional>
void qwer(const std::function<void()> &a)
{
a();
}
int main()
{
int x{0};
auto f{
[x]()mutable
{
std::cout << ++x << std::endl;
}
};
qwer(f);
qwer(f);
qwer(f);
return 0;
}
Выводит:
1
1
1
Есть 2 вопроса:
- Почему компилятор не выдает ошибку? Ведь функция
qwerждет, что ей передадут функцию, а мы ей передаем лямбду, которая, на сколько я знаю, не является функцией. - Почему ,при передачи
fв функциюqwerкаждый раз создается копияf? Ведь при определении функцииqwerпри помощи&мы явно указали, что хотим использовать не копию объекта, а сам объект
Ответы (2 шт):
- std::function умеет работать с лямбдами. пруф
Class template std::function is a general-purpose polymorphic function wrapper. Instances of std::function can store, copy, and invoke any CopyConstructible Callable target -- functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members.
Если я правильно понимаю, там создается копия, потому что тип у f другой. Но достаточно сделать явный тип
std::function<void()> f{ [x]()mutable { std::cout << ++x << std::endl; } };
и все работает как нужно.
Объясню немного 2 вопрос.
Когда вы передаёте в функцию qwer лямбду, то т.к. она принимает аргумент типа function, то создается временный объект на который и ведет ссылка.
Вы можете удостоверится в этом добавив такую строчку в функцию qwer:
std::cout << &a << std::endl; //Вывести адрес
Сама лямбда у вас захватывает x по значению, по этому в каждом временном объекте своя копия x, нужно чтобы лямбда захватывала его по ссылке &x.
Поподробней и более умным языком написано тут.
То есть в вашем случае ссылка function<void()>& ведет на временный объект из-за различий в типах. А сама лямбда захватывает x по значению, а не по ссылке, по этому каждый временный объект работает с копией x.
Немного кода:
auto f{
[&x]()mutable
{
std::cout << ++x << std::endl;
}
};