В строке 1 объявлен шаблон с двумя параметрами – тип указателя на функцию и тип для контекста. В строке 2 объявлено имя класса. В строке 3 объявлен конструктор, который будет сохранять требуемые значения – указатель на функцию и указатель на контекст, переменные для хранения объявлены в строках 6 и 7. В строке 4 осуществляется перегрузка оператора вызова функции, который делает обратный вызов, передавая информацию и сохраненный контекст.
Рассмотренный шаблон также будет работать для указателей на статический метод класса, только необходимо объявить соответствующие типы указателей.
Для указателей на метод-член класса сделаем специализацию шаблона, как это показано в Листинг 28.
template
class CallbackConverter
{
public:
using ClassMethod = void(ClassName::*)(int); // (3)
CallbackConverter(ClassMethod methodPointer = nullptr, ClassName* classPointer = nullptr) // (4)
{
ptrClass = classPointer; ptrMethod = methodPointer;
}
void operator()(int eventID) // (5)
{
ptrClass->*ptrMethod)(eventID); // (6)
}
private:
ClassName* ptrClass; // (7)
ClassMethod ptrMethod; // (8)
};
В строке 1 объявлен шаблон с параметром – именем класса. В строке 2 объявлена специализация шаблона из Листинг 27. Именно эта специализация будет выбрана компилятором, если шаблон инстанциируется указателем на метод класса и указателем на класс. В строке 3 объявлен тип – указатель на метод класса. Этот тип выводится из имени класса, поэтому в шаблоне одного параметра – имени класса – будет достаточно. В строке 4 объявляется конструктор, который будет сохранять требуемые значения – указатель на экземпляр класса и указатель на метод, переменные для хранения объявлены в строках 7 и 8. В строке 5 перегружается оператор вызова функции, который вызывает метод класса.
4.2.3. Исполнитель
Итак, определив объекты для преобразования вызовов, мы теперь можем использовать в шаблоне-инициаторе, определенном в Листинг 25 п. 4.2.1, любые типы аргументов обратного вызова. Пример приведен в Листинг 29.
class Executor // (1)
{
public:
static void staticCallbackHandler(int eventID, Executor* executor) {}
void callbackHandler(int eventID) {}
void operator() (int eventID) {}
};
void ExternalHandler(int eventID, void* somePointer)
{
Executor* ptrClass = (Executor*)somePointer;
}
int main()
{
Executor executor;
int capturedValue = 0;
// (2) External function
using FunctionPointer = void(*)(int, void*);
using FunctionConverter = CallbackConverter
run(FunctionConverter(ExternalHandler, &executor));
// (3) Static method
using StaticPointer = void(*)(int, Executor*);
using StaticConverter = CallbackConverter
run(StaticConverter(Executor::staticCallbackHandler, &executor));
// (4) Member merthod
using MethodPointer = void(Executor::*)(int);
using MethodConverter = CallbackConverter
run(MethodConverter(&Executor::callbackHandler, &executor));
// (5) Functional object
run(executor);
// (6) lambda-expression
auto lambda = [capturedValue](int eventID) {/*it will be called by initiator*/};
run(lambda);
}