lambda выражения в C++
Вот такой вопрос: если lambda функция захватывает данные из вне , то создаётся анонимный класс с перегруженным оператором() (функтором) и полем, а что произойдет , если никакие данные не будут захвачены , то есть сгенерируется аноним.класс без этого поля и все?
//Без захвата переменной:
auto lambda = [](int x, int y) { return x + y; };
class __Lambda {
auto operator()(int x, int y) const {
return x + y;
}
};
//C захватом переменной:
int a = 5;
auto lambda = [a](int x) { return x + a; };
class __Lambda {
int a;
__Lambda(int a_) : a(a_) {}
auto operator()(int x) const { return x + a; }
};
Я правильно понимаю , что это так работает? Или , к примеру , если лямбда функция не захватывает переменные из вне , в ней создаются иные методы?
Ответы (3 шт):
Да, это всегда класс. Проверить легко:
#include <type_traits>
static_assert(std::is_class_v<decltype([]{})>);
Хотя понятно, что после оптимизаций это будет не сильно отличаться от обычной функции.
Нет, не всё. Лямбда без замыкания приводится к указателю на функцию с соответствующим прототипом:
#include <iostream>
int main() {
auto f = [](int x) -> int { return x * x; };
auto g = [](int x) -> int { return x * x * x; };
int (*h)(int);
h = f;
std::cout << h(2) << '\n';
h = g;
std::cout << h(2) << '\n';
}
$ g++ lambda.cpp $ ./a.out 4 8
Лямбда с замыканием так не умеет:
int main() {
int a = 42;
auto f = [a](int x) -> int { return a + x; };
int (*h)(int);
h = f;
}
$ g++ lambda.cpp lambda.cpp: In function ‘int main()’: lambda.cpp:7:9: error: cannot convert ‘main()::<lambda(int)>’ to ‘int (*)(int)’ in assignment 7 | h = f; | ^ | | | main()::<lambda(int)>
В обоих случаях это будут анонимные классы, описанные expr.prim.lambda.3, expr.prim.lambda.5, expr.prim.lambda.19 и др.
Однако, если никакие данные не будут захвачены, то согласно expr.prim.lambda.6 у этого класса будет константный оператор преобразования типа к указателю на функцию. Т.е. ваш первый модельный класс, согласно стандарта, должен иметь примерно такой вид:
auto lambda = [](int x, int y) { return x + y; };
class Lambda_ {
static inline int func_(int x, int y) {
return x + y;
}
typedef decltype(func_) *fptr_;
public:
operator fptr_() const { // expr.prim.lambda.6
return func_;
}
template<typename... Args> // Прототип такой же, как у func_
inline auto operator()(Args... args) const { // expr.prim.lambda.5
return this->func_(args...);
}
// expr.prim.lambda.3, expr.prim.lambda.19 et all
// ...
};