GLU-1: FusedFunctor

Введение

Дальнейшее развитие программы-демонстратора триангуляции средствами GLU.

В качестве эксперимента была опробована методика, названная здесь «fused functors» («слияние функторов»). Это эксперимент, а не пример распространённой или рекомендуемой практики. Суть методики в объединении нескольких действий, выполняемых над одними и теми же элементами массива (первоначально вершинами контура) и/или их последовательными парами (первоначально отрезками, составляющими контур). Можно продолжить на n-ки произвольной длины (например, все последовательные тройки вершин позволяют обработать углы контура). Код здесь: GLUPoly-1.2.7z. Объединение нескольких действий задумано с тем, чтобы выполнять их не за несколько проходов, а за один.

FusedFunctor

Итак, функтор, допускающий «слияние», строго говоря не является функтором в терминах C++, так как не переопределяет operator(). Класс, который можно назвать «FusedFunctor» должен предоставлять следующее.

  • Вложенные типы argument_type (тип обрабатываемых элементов массива) и result_type (результат обработки, возвращаемый в конце, может быть void, например, если begin/fuse складывают элементы в контейнер или выводят в поток).
  • Функции начала процесса void begin (argument_type) и void begin (argument_type, size_t n), в качестве первого параметра принимающие первый обрабатываемый элемент, в качестве n может передаваться общее количество элементов, если оно известно заранее (да, элементы могут поступать произвольным образом, а не выбираться из массива).
  • Функция обработки следующего элемента void fuse (argument_type), вызывается для всех элементов кроме первого в порядке их поступления.
  • Функция завершения процесса result_type end(), возвращающая конечный результат (если result_type не void).

Функционал разбит на три заголовочных файла. На диаграмме ниже показано их содержимое.

Стрелочкой «A ← b» показаны случаи, когда функция b возвращает объект класса A. Назначение этих функций в увеличении удобства использования классов (аналогично std::pairstd::make_pair, чтобы не выписывать явно параметры шаблонов, если они выводимы).

FusedFunctor.h

Функция applyFused применяет fused functor к диапазону, заданному парой итераторов. Если итераторы относятся к категории RandomAccessIterator, то используется вариант begin с указанием количества элементов.

Два fused functor’а можно объединить, используя combineFused. При этом результат второго функтора игнорируется. Данная функция используется в конструкторе Mesh2.

Остальное содержимое файла имеет вспомогательное назначение. Функции fuseVoidBy1, fuseBy1 и fuseBy2 позволяют «конвертировать» обычный функтор в fused functor (соответственно FusedVoidBy1, FusedBy1 и FusedBy2). Первая из них полагает, что функтор не возвращает результата (результат игнорируется). By1-варианты обрабатывают по одной вершине. By2-варианты обрабатывают все последовательные пары, в конце пару (последний элемент, первый элемент). Не-void варианты используют функтор «аккумулятор» для объединения результатов вызовов исходного функтора. По умолчанию используется InPlaceAdd, вызывающий operator+=.

Шаблоны ResultOf и ArgumentOf используются для вычисления типа (через вложенный тип type, такие шаблоны ещё называют метафункциями) результата функтора (для классов по умолчанию используется вложенный тип result_type) и типа аргумента (для классов используется вложенный тип argument_type). ArgumentOf работает и для бинарных функций (но не для функторов-наследников std::binary_function), однако, при необходимости можно либо явно задать тип аргумента в шаблоне, либо определить частную специализацию шаблона ArgumentOf, возвращающую нужный тип. Аналогично можно поступить и с ResultOf, впрочем, этот шаблон несколько «сильнее» засчёт того, что опирается на boost::result_of (который, в свою очередь, использует возможности C++11, если они доступны).

Вспомогательную роль играют boost::type_traits (common_type) и boost::call_traits (для вывода типа параметра из типа аргумента, для пользовательских классов по умолчанию выводится константная ссылка).

FusedForContour.h

В этот заголовочный файл включены средства, предназначенные для использования с объектами Contour, основанные на FusedFunctor.h. FusedPerimeter и FusedArea являются fused functor, и вычисляют соответственно периметр и площадь многоугольника. Они используются в Contour::perimeter() и Contour::area(). FusedContourPushBack заполняет объект контура вершинами.

FusedFunctorTuple.h

Данный файл не проверялся в деле, и, хотя некоторые ошибки относительно 1.1 были исправлены, вполне возможно, что остались ещё.

Функции functorsTuple/functorsTupleVoid можно использовать для объединения нескольких обычных функторов в один функтор, возвращающий n-ку («tuple», «кортеж») результатов (не-Void-вариант). Для конвертирования n-ки fused functor’ов в один fused functor предназначены fuseTuple/fuseVoidTuple (Void-вариант игнорирует результаты). Далее их опять же можно объединить с помощью combineFused (цель которой, собственно, не в объединении пары функторов, а в объединении того, что возвращает результат и того, что не возвращает).

Используется реализация n-ки из boost::fusion.

Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: