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

<p>5.5. Распределитель для статического набора</p><p>5.5.1. Распределение без возврата результатов</p>

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

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

template  // (1)

class StaticDistributorVoid

{

public:

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

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

  template          // (4)

  void operator() (CallData… callData)

  {

    Distribute2(callObjects, callData…);

  }

private:

  std::tuple 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 производятся вызовы сохраненных объектов.

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

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

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

template  // (1)

class StaticDistributorReturn

{

public:

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

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

  template         // (4)

  auto operator() (CallData… callData)

  {

      return DistributeReturn(callObjects, callData…);

  }

private:

  std::tuple callObjects;  // (5)

};

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

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

Перейти на страницу:

Похожие книги