Обратные вызовы в C++ | страница 39
4.4.2. Хранение лямбда-выражений
Почему хранение лямбда-выражений является проблемой?
При объявлении лямбда-выражения компилятор генерирует функциональный объект, который называется объект-замыкание (closure type). Этот объект хранит в себе захваченные переменные и имеет перегруженный оператор вызова функции. Сигнатура оператора повторяет сигнатуру лямбда-выражения, а в теле оператора размещается код выражения. Пример объекта-замыкания приведен в Листинг 38.
>int main()
>{
> int capture = 0;
> [capture](int eventID) {/*this is a body of lambda*/};
> //The following object will be generated implicitly by the compiler from lambda declaration
> class Closure
> {
> public:
> Closure(int value) :capture(value) {}
> void operator() (int eventID)
> {
> /*this is a body of lambda*/
> }
> int capture; //captured value
> };
>}
Как видно из примера, в зависимости от состава захваченных переменных объект-замыкание будет иметь различный тип. То есть, этот тип заранее неизвестен, он будет сгенерирован компилятором. По этой причине тип лямбда-выражения не имеет заранее определенного имени, и мы не можем просто объявить переменную соответствующего типа и присвоить ей значение, как мы делаем, например, в случае использования числовых переменных.
Если лямбда-выражение не захватывает переменные, то стандарт допускает преобразование лямбда-выражения к указателю на функцию. В этом случае объект-замыкание не содержит переменных, что позволяет код лямбда-выражения оформить в виде статической функции и объявить соответствующий оператор преобразования. Таким образом, появляется возможность сохранить лямбда-выражение в переменной типа "указатель на функцию", как показано в Листинг 39.
>int main()
>{
> [](int eventID) {/*this is a body of lambda*/}; // (1)
> //The following object will be generated implicitly by the compiler from lambda declaration
> class Closure // (2)
> {
> public:
> void operator() (int eventID) // (3)
> {
> call_invoker(eventID);
> }
> static void call_invoker(int eventID) { /*this is a body of lambda*/ } // (4)
> using function_pointer = void(*)(int); // (5)
> operator function_pointer() const // (6)
> {
> return call_invoker;
> }
> };
> //Conversion the closure object to the function pointer
> Closure cl; // (7)
> using pointer_to_function = void(*)(int); // (8)