У меня есть случай, когда мне нужно передать лямбду в свободную функцию, которая затем вызовет эту лямбду в другой лямбде. Я привел пример ниже (ссылка):
#include <ranges>
#include <map>
#include <format>
#include <functional>
#include <iostream>
template<typename RANGE, typename LAM>
auto foo(RANGE range, LAM&& lambda) {
return range | std::views::transform(
[&](const auto& element) { return lambda(element); });
}
class boo {
public:
int add {2};
void call_foo(){
std::vector<int> d { 2,3,4,5,6};
auto f = foo(d, [this](int i) {
std::cout << add << std::endl;
return add + i;
});
std::cout << f[0] << f[1] << std::endl;
};
};
int main() {
std::cout << "HELLO" << std::endl;
boo b;
b.call_foo(); // is no longer valid inside the lambda
}
Код segfaults здесь:
std::cout << add << std::endl;
По сути, это потому, что this становится висящим внутри лямбды. Однако я не понимаю, почему это происходит и как этого избежать.
Я также пытался захватить лямбду внутри foo по значению и переместить/вперед, но без положительного результата.





Нет, не this становится висячим, а range и лямбда, к которой вы передаете foo, становятся висячими. Ссылка на range, содержащаяся внутри tranform_view, становится опасной, как только foo возвращается, а лямбда, к которой вы передаете foo, становится висячей в конце полного выражения. Вам нужна ссылка на d и зафиксируйте лямбду по значению во внутренней лямбде:
template <typename RANGE, typename LAM>
auto foo(RANGE& range, LAM&& lambda) {
// ^
return range | std::views::transform(
[lambda](const auto& element) { return lambda(element); });
// ^^^^^^
}
В противном случае возвращаемый transform_view попытается обработать range, который был копией d и вышел за пределы области действия. Вы хотите, чтобы он работал d — и то же самое касается лямбды, которую вы сейчас захватываете по ссылке. Эта лямбда перестает существовать в конце полного выражения, в котором вы вызываете foo. В этом случае вы должны сохранить его во внутренней лямбде или создать его перед вызовом foo, чтобы он сохранился после полного выражения, в котором вы вызываете foo().
С пересылкой лямбды:
template <typename RANGE, typename LAM>
auto foo(RANGE& range, LAM&& lambda) {
return range | std::views::transform(
[lam = std::forward<LAM>(lambda)](const auto& element) {
return lam(element);
});
}
Спасибо! это действительно работает. Когда я попытался реконструировать свой реальный вариант использования, я понял, что он все еще ошибочен. Я думаю, что дополнительный бит, который я добавил (который, как я изначально думал, не изменит область действия), является тем, что причиняет вред и, следовательно, вероятно, вызвано другой проблемой, поэтому я опубликовал отдельный билет: stackoverflow.com/questions/78085914/…
@ATK О, это выглядит интересно! Я мало что знаю о библиотеке {fmt} и смогу посмотреть ее не сегодня, но, возможно, завтра.
Я не думаю, что проблема в захвате
this. Ваша функцияfoo()принимаетvectorпо значению, таким образом копируя его, а затем возвращает представление в эту копию, которая уже не существует к моменту чтения представления после выходаfoo(). Для меня это пахнет неопределенным поведением. У вас все еще будет проблема, если вы изменитеfoo(), чтобы вместо этого использоватьvectorпо ссылке?