Обратные вызовы в C++ | страница 50
До появления стандарта C++17 реализация указанного способа была достаточно сложной: пришлось бы объявлять еще один объект, который наследовался от Callable и осуществлял вызов метода; для создания соответствующего объекта пришлось бы объявить дополнительный перегруженный оператор присваивания, который в качестве входного аргумента принимал указатель на метод. Но в новом стандарте появилась функция std::invoke, которая определяет тип принимаемого объекта вызова и осуществляет вызов для соответствующего типа. Таким образом, для поддержки вызова метода класса необходимо в реализации CallableObject изменить одну-единственную строчку:
>Return operator() (ArgumentList… arguments) override // (8)
>{
> //return storedArgument(arguments…);
> return std::invoke(storedArgument, arguments…); // (9)
>}
На удивление просто, не правда ли?
Использование универсального аргумента для вызова метода класса представлено в Листинг 50.
>struct CallbackHandler
>{
> void handler1(int eventID) {};
> bool handler2(int eventID, int contextID) { return false; };
>};
>int main()
>{
> CallbackHandler callbackObject;
> UniArgument
> UniArgument
> argument1 = &CallbackHandler::handler1; // (3)
> argument2 = &CallbackHandler::handler2; // (4)
> argument1(&callbackObject, 100); // (5)
> argument2(&callbackObject, 0, 1); // (6)
>}
В строках 1 и 2 объявлены универсальные аргументы для вызова соответствующих методов класса. Как видим, в сигнатуре функции первый параметр является типом класса, для которого будут вызываться соответствующие методы. В строках 3 и 4 производится настройка методов, в строках 5 и 6 – вызовы методов для экземпляра соответствующего класса.
Итак, универсальный аргумент практически готов. Нам осталось реализовать оператор копирования, оператор присваивания и некоторые другие операции. Но мы этим заниматься не будем: разработчики стандартной библиотеки уже обо всем позаботились, поэтому темой следующей главы будет обзор инструментов STL для организации обратных вызовов24.
4.6. Использование стандартной библиотеки
4.6.1. Организация вызовов
В стандартной библиотеке имеется полиморфный класс – оболочка std::function, предназначенная для организации вызовов различных типов. Этот класс идеально подходит на роль универсального аргумента. Кроме рассмотренных техник стирания типа и настройки сигнатуры, в нем реализовано множество других вещей: конструктор копирования, оператор присваивания, поддержка указателей на методы класса, проверка настройки аргумента, локальный буфер для хранения аргумента и многое другое. Мы не будем рассматривать реализацию