Я пытаюсь справиться с лямбдами в C++.
Здесь мой код (переменные, упрощенные для понимания):
template <typename Container>
void do_function(const Container& c, const item &w){
complex<double> a(w.x1, w.y1);
complex<double> b(w.x3, w.y3);
for_each(begin(c), end(c), [] {
p->inner_function(a, b);
});
}
Я знаю, что p ничего не значит, это просто для того, чтобы проиллюстрировать, что я хочу делать.
По сути, я хочу использовать эту функцию для любого типа контейнера (list/vector и т.д.), Который содержит экземпляры указателей абстрактного класса Animal. Все эти экземпляры имеют реализацию "inner_function (complex, complex)".
Я хочу вызвать эту функцию для каждого из них в цикле for_each, используя lambdas в C++ 11..
Однако примеры онлайн все немного запутывают.
Кажется, вы хотите использовать
std::for_each(std::begin(c), std::end(c), [=](Animal* p) { p->inner_function(a, b); });
Ваша лямбда-функция должна будет принять один аргумент, поскольку std::for_each()
ожидает функцию, которая может быть вызвана с результатом *std::begin(c)
. Аргументы должны быть явно объявлены. Вам также необходимо выбрать способ захвата аргументов a
и b
. Использование []
означает, что нет захваченного контекста, и вы не можете получить доступ к каким-либо локальным переменным вообще. Вы можете использовать
[=]
чтобы зафиксировать все переменные в контексте по значению.[&]
чтобы фиксировать все переменные в контексте по ссылкам.[=,&a]
будет захватывать b
по значению и a
в качестве ссылки.[&,b]
то же самое, но начиная с другого значения по умолчанию[&a,b]
то же, но явно перечисляет все аргументы. Может быть проще использовать выражение std::bind()
, на самом деле:
std::for_each(std::begin(c), std::end(c), std::bind(&Animal::inner_function, _1, a, b));
Так как вы не задавали вопрос, неясно, в чем вопрос.
Если Container
будет vector<Animal*>
, list<shared_ptr<Animal>>
т.д., Тогда я думаю, что вы хотите:
for_each(begin(c), end(c), [&](typename Container::value_type p) {
p->inner_function(a, b);
});
Чтобы также поддерживать unique_ptr
, вы можете сделать его typename Container::value_type const &p
.
Или используйте "диапазон для цикла":
for(auto p : c) {
p->inner_function(a, b);
}
Точно так же, как опция auto &
разрешить не скопировать p
.
typename Container::value_type
Контейнер должен содержать указатели, чтобы использовать полиморфизм. Я буду использовать умные указатели:
std::vector<std::unique_ptr<Animal>> v;
item w;
do_function(v, w);
Алгоритм std::for_each
передает каждый элемент в функтор. Он передает их таким образом, что функтор может принимать аргумент либо по значению, либо по ссылке при необходимости. unique_ptr
необходимо использовать по ссылке:
for_each(begin(c), end(c), [] (std::unique_ptr<Animal> &p) {
p->inner_function(a, b);
});
Функтору также нужен доступ к a
и b
. Вы можете зафиксировать их явно:
[a,b] (std::unique_ptr<Animal> &p) {
Или, как говорит Стив Джессоп, просто использовать диапазон на основе for
, что гораздо проще. С unique_ptr
это выглядело бы так:
for(auto &p : c) {
p->inner_function(a, b);
}