Выбрать главу

  int operator() (int eventID)

  {

    return 10;

  }

};

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 results = DistributeReturn( std::tuple(fo, ExternalHandler, lambda), eventID);  // (1)

  int foRes = std::get<0>(results);             // (2)

  SResult ExtRes = std::get<1>(results);        // (3)

  double lambdaRes = std::get<2>(results);      // (4)

  auto [foRes1, ExtRes1, lambdaRes1] = results; // (5)

  auto [foRes2, ExtRes2, lambdaRes2] = DistributeReturn(std::tuple(fo, ExternalHandler, lambda), eventID);  // (6)

}

После выполнения распределения в строке 1 в переменную results помещен кортеж с результатами выполнения вызова. В строках 2, 3, 4 показано получение результатов с помощью запроса элементов кортежа по индексу, в строке 5 показано использование структурных привязок. В строке 6 показано, как можно использовать структурные привязки без промежуточной переменной results. Обход кортежа здесь не рассматривается, поскольку он был подробно описан в п. 5.3.3.

5.5. Распределитель для статического набора

5.5.1. Распределение без возврата результатов

До сих пор мы выполняли распределение с помощью функции, что вызывает определенные неудобства. Во-первых, вызов распределяющей функции получается громоздким, потому что приходится перечислять все объекты, участвующие в распределении. Во-вторых, требуются дополнительные операции, потому что в зависимости от способа настройки либо объекты вызова, либо аргументы сигнатуры необходимо упаковать в кортеж. Хорошим решением было бы предварительно сохранить нужные объекты, для чего нам понадобится распределитель в виде класса. Реализация приведена в Листинг 75.

Листинг 75. Распределитель для статического набора получателей

template<typename… CallObjects>  // (1)

class StaticDistributorVoid

{

public:

  StaticDistributorVoid (CallObjects… objects) : callObjects(objects…) {}  // (2)

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

  template<typename… CallData>          // (4)

  void operator() (CallData… callData)

  {

    Distribute2(callObjects, callData…);

  }

private:

  std::tuple<CallObjects…> callObjects;  // (5)

};

В строке 1 объявлен шаблон класса, параметром которого выступает пакет объектов вызова. Кортеж для хранения объектов объявлен в строке 5, он инициализируется в конструкторе 2. Для доступа к кортежу реализован метод 3, который позволяет, если необходимо, изменить его содержимое.

В строке 4 объявлен перегруженный оператор, который осуществляет распределение. Этот оператор вызывает распределяющую функцию (реализацию см. Листинг 69 п. 5.3.3), которую при желании можно сделать членом класса.

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

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

struct FO

{

  void operator() (int eventID) {}

  void callbackHandler(int eventID) {}

};

void ExternalHandler(int eventID) {}

int main()

{

  FO fo;

  int eventID = 0;

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

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

  StaticDistributorVoid distributor(ExternalHandler, fo, callbackToMethod, lambda);  // (1)

  distributor(eventID);  // (2)

}

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

5.5.2. Распределение с возвратом результатов

Если нужно получить значения, возвращаемые вызовами, то в распределителе необходимо модифицировать перегруженный оператор (Листинг 77).

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

template<typename… CallObjects>  // (1)

class StaticDistributorReturn

{

public:

  StaticDistributorReturn(CallObjects… objects) : callObjects(objects…) {}  // (2)

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

  template<typename… CallData>         // (4)

  auto operator() (CallData… callData)

  {

      return DistributeReturn(callObjects, callData…);

  }

private:

  std::tuple<CallObjects…> callObjects;  // (5)

};

В строке 4 объявлен перегруженный оператор с возвращаемым типом auto. Указанный тип будет выведен из значения, возвращаемого соответствующей распределяющей функцией. (реализацию см. в Листинг 73 п. 5.4.1).