Обратные вызовы в C++ | страница 40
> pointer_to_function fptr = cl; // (9)
> //Conversion a lambda to the function pointer
> fptr = [](int eventID) {/*this is a body of lambda*/}; // (10)
>}
В строке 1 объявлено лямбда-выражение, в строке 2 объявлен объект-замыкание. Подчеркнем: этот объект здесь всего лишь для демонстрации, чтобы показать, как он будет сгенерирован компилятором. В реальном коде такой объект объявлять не нужно, компилятор его создаст при объявлении лямбда-выражения.
В строке 3 объявлен перегруженный оператор, который вызывает статическую функцию 4. В той функции размещается код лямбда-выражения.
В строке 5 объявлен тип указателя на функцию, в строке 6 объявлен оператор преобразования типа. Реализация оператора возвращает указатель на статическую функцию 4.
В строках 7–9 показано, как осуществляется преобразование функционального объекта к указателю на функцию. В строке 7 объявлен объект-замыкание, в строке 8 объявлен тип указателя на функцию. В строке 9 объявляется переменная этого типа и вызывается перегруженный оператор присваивания 6, который возвращает указатель на функцию. Теперь в переменной fptr будет храниться указатель на статическую функцию, которая была объявлена в соответствующем функциональном объекте.
В строке 10 продемонстрировано преобразование лямбда-выражения к указателю на функцию. Все действия, описанные выше с использованием функционального объекта, будут неявно сгенерированы компилятором.
Итак, если лямбда-выражение не захватывает переменные, то сохранить его как аргумент достаточно просто: объявляется указатель на функцию, которому присваивается соответствующее выражение. Однако в случае захвата переменных ситуация меняется. Теперь в объекте-замыкании будут храниться захваченные переменные, и компилятор не может код лямбда-выражения разместить в статической функции, ведь статическая функция не имеет доступа к членам класса. Поэтому указанный код вставляется в функцию-член класса. Казалось бы, почему не объявить указатель на функцию-член класса и присвоить ему значение? Проблема в том, что для этого необходимо знать тип класса, т. е. тип объекта-замыкания. А этот тип заранее неизвестен, он генерируется на этапе компиляции. Таким образом, здесь невозможно объявить указатель на метод и присвоить ему значение.
Если необходимо хранить лямбда-выражение в локальной переменной, можно использовать тип auto. Это означает, что компилятор подставит соответствующий тип, который будет сгенерирован из объявления лямбда-выражения (см. Листинг 40).