Библиотека сайта rus-linux.net
ITK
Глава 9 из книги "Архитектура приложений с открытым исходным кодом", том 2.Оригинал: ITK
Авторы: Luis Ibanez, Brad King
Перевод: А.Панин
9.3. Выученные уроки
Повторное использование
- Во-первых, применение объектно-ориеннтированного программирования и в особенности корректной процедуры создания иерархий классов, в которых стандартные функции реализуются в базовых классах.
- Во-вторых, использование парадигмы обобщенного программирования, реализуемое путем повсеместного использования шаблонов языка C++, а также реализации функций программы, идентифицируемых как шаблоны.
- В-третьих, широкое использование макросов C++ также позволило повторно использовать стандартные фрагменты кода, которые требуются в миллиарде мест тулкита.
Большая часть этих пунктов сегодня может показаться банальной и очевидной, но в в момент начала разработки ITK в 1999 году некоторые из них не были настолько очевидными. В частности, при поддержке большинством компиляторов языка C++ шаблонов, эта поддержка в точности не соответствовала однозначному стандарту. Даже сегодня такие решения, как применение парадигмы обобщенного программирования и использование реализации с широким применением шаблонов продолжают вызывать споры в сообществе. Это утверждение подчеркивается фактом существования сообществ, участники которых предпочитают использовать ITK с помощью уровня кода для совместимости с языками Python, Tcl или Java.
Обобщенное программирование
Применение парадигмы обобщенного программирования было одной из определяющих особенности реализации ITK черт. В 1999 году это решение было сложным, так как в то время поддержка компиляторами шаблонов C++ была значительно фрагментированной и стандартная библиотека шаблонов (Standard Template Library (STL)) все еще рассматривалась в некоторой степени как экзотическое дополнение.
Image
, экземпляр которого может быть создан следующим образом:
typedef unsigned char PixelType; const unsigned int Dimension = 3; typedef itk::Image< PixelType, Dimension > ImageType; ImageType::Pointer image = ImageType::New();
В этом коде разработчик приложения выбирает тип, используемый для представления пикселей изображения, а также количество плоскостей изображения в виде сетки в пространстве. В примере мы выбрали для использования 8-битные
пиксели, представленные с помощью значений типа unsigned char
для 3-х мерного изображения. Благодаря низкоуровневой обобщенной реализации, в ITK возможно создание экземпляров классов изображений для любых типов пикселей с любым количеством плоскостей.
Для возможности записи этих выражений разработчикам ITK пришлось реализовать класс Image
с особой осторожностью в отношении предположений о типе пикселей. Как только разработчик приложения создал экземпляр класса изображения определенного типа, он может создавать объекты этого типа или перейти к созданию экземпляров классов фильтров изображений, типы которых, в свою очередь, зависят от типа изображения. Например:
typedef itk::MedianImageFilter< ImageType, ImageType> FilterType;
FilterType::Pointer median = FilterType::New();
Алгоритмические особенности некоторых фильтров изображений ограничивают набор актуальных типов пикселей, который они поддерживают. Например, некоторые фильтры изображений ожидают, что тип пикселей изображения будет представлен целочисленными скалярными величинами, в то время, как некоторые другие фильтры ожидают типа пикселя в виде векторов из величин с плавающей точкой. При создании экземпляров классов изображений с неподходящими типами пикселей эти фильтры станут причиной ошибок компиляции или ошибочных результатов расчетов значений пикселей изображения. Для предотвращения некорректного создания объектов и упрощения поиска причин ошибок компиляции в рамках ITK был применен метод концептуальных проверок (concept checking), основанный на принудительном использовании определенных ожидаемых возможностей типов с целью раннего выявления ошибок с выводом понятных человеку сообщений об ошибках.
Шаблоны C++ также используются в определенных системах тулкита в форме шаблонного метапрограммирования (Template Metaprogramming) для повышения производительности кода, а в особенности для разворачивания циклов, которые используются для расчета значений низкоразмерных векторов и матриц. По иронии судьбы, со временем мы обнаружили, что определенные компиляторы научились определять места, где необходимо осуществить разворачивание циклов и в некоторых случаях им больше не требуется выражений шаблонного метапрограммирования.
Продолжение статьи: Знать, когда остановиться