Введение

Книга Андрея Александреску "Современный дизайн C++: Общее программирование и применение шаблонов проектирования" – книга Андрея Александреску, опубликованная в 2001 году издательством Addison Wesley. Скотт Майерс назвал её "одной из самых важных книг по C++". В книге рассматривается и исследуется техника программирования на C++, известная как метапрограммирование шаблонов. Хотя Александреску и не изобрел эту технику, он сделал её популярной среди программистов. Книга содержит решения практических задач, с которыми могут столкнуться разработчики на C++. Несколько выражений из книги стали общеупотребимыми терминами в C++-сообществе: современный C++ (в отличие от стиля C/C++), проектирование, основанное на политиках, и типелиста. Весь код, описанный в книге, свободно доступен в его библиотеке Loki. С 2001 года книга была переиздана и переведена на несколько языков.

Дизайн на основе политики

Дизайн, основанный на политиках, также известный как проектирование классов на основе политик или программирование на основе политик, — это термин, используемый в современном дизайне C++ для подхода к проектированию, основанного на идиоме для C++, известной как политики. Он описан как вариант шаблона «Стратегия», работающий во время компиляции, и связан с метапрограммированием шаблонов C++. Впервые он получил широкое распространение в C++ благодаря книге Андрея Александреску «Modern C++ Design» и его колонке «Generic<Programming>» в журнале C/C++ Users Journal, и в настоящее время тесно связан с C++ и D, поскольку требует компилятора с надежной поддержкой шаблонов, что было не распространено до 2003 года. Предыдущие примеры этого подхода к проектированию, основанные на параметризованном обобщенном коде, включают параметрические модули (функторы) языков ML и аллокаторы C++ для политики управления памятью. Центральной идиомой в дизайне, основанном на политиках, является шаблон класса (называемый классом-хостом), принимающий несколько параметров типа в качестве входных данных, которые инстанцируются типами, выбранными пользователем (называемыми классами политик), каждый из которых реализует конкретный неявный интерфейс (называемый политикой) и инкапсулирует некоторые ортогональные (или преимущественно ортогональные) аспекты поведения инстанцированного класса-хоста. Предоставляя класс-хост в сочетании с набором различных, готовых реализаций для каждой политики, библиотека или модуль может поддерживать экспоненциальное количество различных комбинаций поведения, разрешаемых во время компиляции и выбираемых путем комбинирования различных предоставленных классов политик при инстанцировании шаблона класса-хоста. Кроме того, написав пользовательскую реализацию данной политики, библиотеку, основанную на политиках, можно использовать в ситуациях, требующих поведения, не предусмотренного разработчиком библиотеки. Даже в тех случаях, когда используется не более одной реализации каждой политики, разложение класса на политики может помочь процессу проектирования, повышая модульность и выделяя места, где были приняты ортогональные решения по проектированию. Хотя сборка программных компонентов из взаимозаменяемых модулей — это не новая концепция, дизайн, основанный на политиках, представляет собой инновацию в том, как он применяет эту концепцию на (относительно низком) уровне определения поведения отдельного класса. Классы политик имеют некоторое сходство с функциями обратного вызова, но отличаются тем, что, вместо того чтобы состоять из одной функции, класс политики обычно содержит несколько связанных функций (методов), часто в сочетании с переменными состояния или другими возможностями, такими как вложенные типы. Класс-хост, основанный на политиках, можно рассматривать как тип метафункции, принимающей набор поведения, представленный типами, в качестве входных данных и возвращающей в качестве выходных данных тип, представляющий результат объединения этих поведений в функционирующее целое. (В отличие от метафункций MPL, однако, выход обычно представлен самим инстанцированным классом-хостом, а не вложенным типом вывода.) Ключевой особенностью идиомы политики является то, что, как правило (хотя это и не строго необходимо), класс-хост будет происходить от (становиться дочерним классом) каждого из его классов политик, используя (публичное) множественное наследование. (Альтернативой является то, что класс-хост просто содержит переменную-член каждого типа класса политики или наследует классы политик в частном порядке; однако публичное наследование классов политик имеет важное преимущество: класс политики может добавлять новые методы, унаследованные инстанцированным классом-хостом и доступные для его пользователей, о которых сам класс-хост даже не должен знать.) Примечательной особенностью этого аспекта идиомы политики является то, что по отношению к объектно-ориентированному программированию политики инвертируют взаимосвязь между базовым классом и производным классом: в то время как в ООП интерфейсы традиционно представлены (абстрактными) базовыми классами, а реализации интерфейсов — производными классами, в дизайне, основанном на политиках, производный (хост) класс представляет интерфейсы, а базовые (классы политик) — реализуют их. В случае политик публичное наследование не представляет собой отношение «является» между хостом и классами политик. Хотя это традиционно рассматривалось бы как признак дефекта проектирования в контексте ООП, это не применимо в контексте идиомы политики. Недостатком политик в их текущей реализации является то, что интерфейс политики не имеет прямого, явного представления в коде, а определяется неявно, посредством «утиной типизации», и должен быть задокументирован отдельно и вручную, в комментариях. Основная идея заключается в использовании анализа общности и изменчивости для разделения типа на фиксированную реализацию и интерфейс, класс, основанный на политиках, и различные политики. Трудность заключается в том, чтобы определить, что поместить в основной класс, а какие политики следует создать. В вышеупомянутой статье дается следующий ответ: везде, где нам потребуется принять возможное ограничивающее решение по проектированию, мы должны отложить это решение, делегировать его соответствующим образом названной политике. Классы политик могут содержать реализацию, определения типов и так далее. По сути, разработчик основного класса шаблона определит, что классы политик должны предоставлять, какие точки настройки им необходимо реализовать. Создание хорошего набора политик может быть деликатной задачей, именно столько, сколько необходимо (например, минимум). Различные точки настройки, которые связаны друг с другом, должны быть объединены в один аргумент политики, например, политику хранения, политику проверки и так далее. Графические дизайнеры могут давать имена своим политикам, которые представляют концепции, а не те, которые представляют операции или незначительные детали реализации. Дизайн, основанный на политиках, может включать другие полезные методы. Например, шаблонный метод можно переинтерпретировать для времени компиляции, чтобы основной класс имел скелетный алгоритм, который в точках настройки вызывает соответствующие функции некоторых политик. Это будет достигнуто динамически с помощью концепций в будущих версиях C++.

Библиотека Локи

Loki — это название библиотеки программного обеспечения на C++, написанной Андреем Александреску в рамках его книги «Современный дизайн C++». Библиотека активно использует метапрограммирование шаблонов C++ и реализует несколько часто используемых инструментов: typelist, functor, singleton, умные указатели, фабрику объектов, visitor и мультиметоды. Изначально библиотека была совместима лишь с двумя наиболее соответствующими стандарту компиляторами C++ (CodeWarrior и Comeau C/C++), но последующие усилия сделали её пригодной для использования с широким спектром компиляторов (включая устаревшие Visual C++ 6.0, Borland C++ Builder 6.0, Clang и GCC). Разработчики компиляторов использовали Loki в качестве эталона совместимости, что способствовало увеличению числа компиляторов, соответствующих стандарту. Поддержка и дальнейшая разработка Loki продолжаются благодаря сообществу разработчиков с открытым исходным кодом, возглавляемому Питером Кюммелем и Ричардом Спозато в рамках проекта SourceForge. Постоянный вклад множества участников улучшил общую надёжность и функциональность библиотеки. Loki больше не связана с книгой, поскольку содержит множество новых компонентов (например, StrongPtr, Printf и Scopeguard). Loki послужила источником вдохновения для аналогичных инструментов и функциональности, которые теперь также представлены в библиотеке Boost.