Почему нельзя использовать диапазоны для функциональности библиотеки каналов?

Джонатан Боккара (автор Fluent C++) написал библиотеку под названием pipe.

Этот "конвейер", как говорится на главной странице репозитория, не похож на использование диапазонов, хотя он выглядит одинаково: он основан не на ленивом извлечении, а скорее на активном толчке. Но заявлено, что нельзя использовать библиотеку диапазонов для выполнения различных "конвейерных" операций. Например:

  • unzip - Возьмите заархивированный вход - по сути, диапазон k-кортежей - и создайте k отдельных независимых выходных данных.
  • fork- создать несколько (независимых) копий контейнера / диапазона.

Я не совсем понимаю, почему в принципе так. (Конечно, за исключением диапазонов, в которых вы не можете получить конечный итератор / дозорный.)

1 ответ

Решение

По сути, обсуждается разница между методологией обработки на основе push и методом pull. В системе push, подобной этой библиотеке каналов, вы устанавливаете цепочку обработки, и каждый шаг обработки передает свои данные непосредственно в следующий. В системе вытягивания, подобной диапазонам, вы устанавливаете представление данных, к которому вы можете обращаться и изменять по мере необходимости. Обработка не происходит сама по себе; это происходит только тогда, когда кто-то пытается поглотить диапазон.

В unzip а также fork Обе операции являются операциями "один ко многим": они принимают один ввод и сопоставляют его со многими операциями обработки.

Как система push, библиотека каналов может обрабатывать операции "один ко многим" из-за структуры своего API. Операция представлена ​​вызовом функции; ввод подразумевается точкой использования (используя>>=или передать его процессору). Параметры функции определяют ее вывод (без учета параметров, предназначенных для самого процессора). А поскольку функции C++ могут иметь произвольное количество параметров, операция сопоставления "один ко многим", естественно, не выполняется. Вы просто поставляете соответствующие процессоры для различных выходов.

В вытягивающей системе диапазоны основаны на возвращаемых значениях. В C++ нет языкового механизма для возврата нескольких значений, поэтому лучшее, что мы можем сделать, - это вернуть "значение", представляющее несколько значений.

Однако цепочка адаптера диапазона в конечном итоге основана на том, что входы являются диапазонами. И "значение", представляющее несколько значений, само по себе не является диапазоном. Он может содержать диапазоны, но это не делает его диапазоном.

Итак, теперь вы должны взять этот совершенно определенно "не диапазонный" тип и заставить все ваши адаптеры диапазона работать с ним. Применение адаптера диапазона должно транслировать эту операцию по типу, создавая операцию "многие ко многим". Сделать это непросто.

Но что более важно... вероятно, это не то, что вам нужно. если тыforkдиапазон, то вы почти наверняка захотите выполнить другую обработку реплицированных диапазонов. И это полностью исключает возможность использования|операция для этого. Вам нужно будет создать способы применения адаптеров к определенным частям этих кортежей диапазонов. И эти способы все больше будут выглядеть как процессор на основе push-уведомлений.

В конце концов, система pull-style имеет только один выход на каждом уровне. Это только часть основной концепции такого API: каждый шаг обработки генерирует в диапазон. Это имеет свои преимущества (ленивая обработка), но представление операций "один ко многим" является одним из его слабых мест.

Диапазоны, безусловно, могут иметь unzip функция (forkдействительно просто копирует диапазон). Но это не было бы|адаптер стиля; это будет функция, которая принимает диапазон некоторого разложимого типа и возвращает кортеж диапазонов. Если вы хотите выполнить с ними дополнительную обработку, вам нужно будет сохранить кортеж в значении, получить доступ к отдельным элементам и использовать их по своему усмотрению.

Другие вопросы по тегам