Краткий ответ
Это просто означает, что лямбды, которые ничего не захватывают, могут быть преобразованы в указатель функции с такой же сигнатурой:
auto func = [](int x) { return x * 2; };
int (*func_ptr)(int) = func; // legal.
int y = func_ptr(2); // y is 4.
А захват делает его незаконным:
int n = 2;
auto func = [=](int x) { return x * n; };
int (*func_ptr)(int) = func; // illegal, func captures n
Длинный ответ
Лямбда - это сокращение для создания функтора:
auto func = [](int x) { return x * 2; };
Эквивалентно:
struct func_type
{
int operator()(int x) const { return x * 2; }
}
func_type func = func_type();
В этом случае func_type
- это «тип закрытия» and operator()
- это «оператор вызова функции». Когда вы берете адрес лямбды, вы как бы объявляете статический operator()
и берете его адрес, как и любая другая функция:
struct func_type
{
static int f(int x) { return x * 2; }
}
int (*func_ptr)(int) = &func_type::f;
Когда вы захватили переменные, они становятся членами func_type
. operator()
зависит от этих членов, поэтому его нельзя сделать статическим:
struct func_type
{
int const m_n;
func_type(int n) : m_n(n) {}
int operator()(int x) const { return x * m_n; }
}
int n = 2;
auto func = func_type(n);
Обычная функция не имеет понятия переменных-членов. Следуя этой мысли, лямбды можно рассматривать как обычные функции, только если они не имеют переменных-членов.