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 шт):

Автор решения: HolyBlackCat

Да, это всегда класс. Проверить легко:

#include <type_traits>
static_assert(std::is_class_v<decltype([]{})>);

Хотя понятно, что после оптимизаций это будет не сильно отличаться от обычной функции.

→ Ссылка
Автор решения: Stanislav Volodarskiy

Нет, не всё. Лямбда без замыкания приводится к указателю на функцию с соответствующим прототипом:

#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)>
→ Ссылка
Автор решения: Serge3leo

В обоих случаях это будут анонимные классы, описанные 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
    // ...
};
→ Ссылка