Обратные вызовы в C++ | страница 39



4.4.2. Хранение лямбда-выражений

Почему хранение лямбда-выражений является проблемой?

При объявлении лямбда-выражения компилятор генерирует функциональный объект, который называется объект-замыкание (closure type). Этот объект хранит в себе захваченные переменные и имеет перегруженный оператор вызова функции. Сигнатура оператора повторяет сигнатуру лямбда-выражения, а в теле оператора размещается код выражения. Пример объекта-замыкания приведен в Листинг 38.

Листинг 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.

Листинг 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)