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




Пример использования распределителя приведен в Листинг 78.

Листинг 78. Использование распределителя для статического набора с возвратом результатов

>struct FO

>{

>  int operator() (int eventID) { return 10; }

>  int callbackHandler(int eventID) { return 0; }

>};


>struct SResult

>{

>  unsigned int code;

>  const char* description;

>};


>SResult ExternalHandler(int eventID)

>{

>  return SResult{ 1, "this is an error" };

>}


>int main()

>{

>  FO fo;

>  int eventID = 0;

>  auto lambda = [](int eventID) { return 0.0; };

>  auto callbackToMethod = std::bind(&FO::callbackHandler, fo, std::placeholders::_1);


>  StaticDistributorReturn distributor(ExternalHandler, fo, callbackToMethod, lambda);  // (1)


>  auto [resExtHandler, resFoOperator, resFoMethod, resLambda] = distributor(eventID);  // (2)

>}


В строке 1 объявляется распределитель, в конструктор передаются объекты вызова. Через перегруженный оператор 2 производятся вызовы хранимых объектов, результаты возвращаются с помощью структурных привязок.


К сожалению, мы не можем использовать рассмотренную реализацию для объектов, которые не возвращают результатов. Это связано с тем, что результаты выполнения вызовов возвращаются через кортеж, а он не может хранить типы void. Для таких вызовов нужно использовать реализацию, рассмотренную в предыдущем параграфе.

5.5.3. Параметризация возвращаемого значения

Итак, у нас имеется отдельная реализация распределителя для случая, когда результаты вызовов не требуются, и отдельная реализация для случая, когда необходимо получать возвращаемые значения. Обе реализации одинаковы, за исключением перегруженного оператора. Как сделать общую реализацию для обеих случаев? Разместить два перегруженных оператора в одном классе не получится, потому что они различаются только типом возвращаемого значения. Можно предложить следующее решение: ввести в шаблон дополнительный параметр, который указывает, нужно ли возвращать результаты выполнения вызовов, и в зависимости от этого по-разному формировать перегруженный оператор с помощью условной компиляции. Реализация приведена в Листинг 79.

Листинг 79. Условная компиляция в зависимости от типа возвращаемого значения

>template  // (1)

>class StaticDistributor

>{

>public:

>  StaticDistributor(CallObjects… objects) : callObjects(objects…) {}  // (2)

>  auto& tuple() { return callObjects; }  // (3)


>  template 

>  auto operator() (CallData… callData)  // (4)

>  {


>#define callObject std::get<0>(callObjects)          // (5)