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



Листинг 40. Сохранение лямбда-выражения в локальной переменной

>int capture = 10;


>auto lambda = [capture](int eventID) {/*this is a body of lambda*/};


>lambda(10); //lambda call


Однако указанный способ не будет работать, когда требуется сохранить лямбда-выражение в классе. Мы не можем объявить переменную – член класса с типом auto, потому что это означало бы объявление переменной заранее не определенного типа, что не допускается.

Организовать хранение лямбда-выражения внутри класса можно с помощью шаблона, в котором тип выражения будет параметризован. Однако при инстанциировании шаблона переменной, предназначенной для хранения, значение должно быть присвоено в конструкторе. Это нельзя сделать позже, потому что в объекте-замыкании, генерируемым компилятором, запрещен оператор присваивания. Это и понятно: поскольку тип каждого объявленного лямбда-выражения является уникальным, то мы не можем ему ничего присваивать, кроме самого себя.

Добавим в реализацию инициатора, описанного в Листинг 37 п. 4.4.1, два конструктора. Один конструктор будет с переменной – аргументом обратного вызова для инициализации члена класса. Другой конструктор будет без аргументов (конструктор по умолчанию), чтобы оставить возможность отложенной настройки (Листинг 41).

Листинг 41. Инициатор с дополнительными конструкторами

>template

>class Initiator

>{

>public:

>  Initiator() {}

>  Initiator(const CallbackArgument& argument) : callbackHandler(argument) {}


>  void setup(const CallbackArgument& argument)

>  {

>    callbackHandler = argument;

>  }


>  void run()

>  {

>    int eventID = 0;

>    //Some actions

>    callbackHandler(eventID);

>  }


>private:

>  CallbackArgument callbackHandler;

>};


Для любых типов аргументов обратного вызова, кроме лямбда-выражений, допускается использование обоих конструкторов. Для лямбда-выражений допускается использование только конструктора с аргументом, при попытке использования конструктора по умолчанию компилятор выдаст ошибку. Кроме того, в этом случае нельзя будет вызвать метод setup – также будет сгенерирована ошибка. Таким образом, использование инициатора с лямбда-выражением не предполагает динамической модификации: настройка происходит один раз в конструкторе при инстанциировании шаблона, и больше изменить ее нельзя20.

А какой тип аргумента нам указывать при инстанциировании шаблона, ведь тип лямбда-выражения является анонимным? Для этой цели мы будем использовать ключевое слово