Метапрограммирование на C++

Что такое метапрограммирование - в двух словах

Классика жанра: книга одного из основоположников современного подхода к метапрограммированию в языке C++

Современное проектирование на С++: Обобщенное программирование и прикладные шаблоны проектирования: подробнее

Андрей Александреску
Современное проектирование на С++: Обобщенное программирование и прикладные шаблоны проектирования

Под метапрограммированием понимается создание программ, результатом работы которых являются другие программы - обычно в исходных кодах. То есть когда компилятор C++ генерирует машинные коды - это не метапрограммирование. А когда C++ программа генерирует скрипт на SQL для внесения данных в реляционную базу данных - это как раз метапрограммирование.

Данный вид метапрограммирования встречается в поисковом движке FAIND несколько раз.

К примеру, результаты поиска могут сохраняться в нескольких форматах (см. здесь), в том числе в виде файла SQL скрипта. Затем этот скрипт используется для внесения результатов поиска в таблицы БД.

Другой, более сложный пример метапрограммирования используется в рамках проекта в компиляторе Ygres. Этот инструмент читает программу, описывающую способ преобразования предложений на естественном языке, и создает файл с C++ кодом (если Вы загружали исходные тексты библиотеки LEM, то сгенерированные файлы находятся в LEM\ai\ygres). Затем сгенерированный C++ код компилируется транслятором C++ и дает оптимизированный, производительный код. Нелишне будет напомнить, что первые трансляторы C++, созданные его автором Б. Страуструпом, представляли именно такие метатрансляторы в C-код.

Прием с трансляцией кода в программу на другом языке используется достаточно часто - при создании новых языков программирования (когда вместо написания собственного кодогенератора проще использовать портабельный ассемблер - язык C), в научных числодробилках (а придумали этот прием программисты, работавшие на Фортране, чтобы по входным данным генерировать текст программы с развернутыми циклами, оптимизированными численными методами и т.д.).

Для программистов, работающих на .NET Framework, доступны средства т.н. reflection - в пространствах имен System::Reflection и System::Type собраны классы, позволяющие получать о любом типе информацию (состав полей, их тип и так далее), создавать на лету новые классы и т.д. Наконец, для C++ есть библиотека, позволяющая на лету компилировать и генерировать исполняемый код (используется урезанный компилятор gcc, который портирован под любое устройство, способное исполнять команды).

Вышеперечисленные случаи метапрограммирования связаны с наличием внеязыковых средств (программ). Для нас же сейчас будет интересовать другое проявление метапрограммирования - с использованием только стандартных средств языка C++, прежде всего шаблонов и (иногда) директив препроцессора. На самом деле применение только внутриязыковых инструментов C++ позволяет писать удивительно компактные и оптимизированные алгоритмы.

Единственная серьезная проблема, возникающая в чистом метапрограммировании на C++ - отсутствие каких-либо средств отладки метапрограмм. Любой C++ программист сталкивался с ситуацией, когда написанный код вызывает у компилятора приступ диареи в виде загадочных сообщений об ошибках в глубинах STL/BOOST - виной всему оказывается неправильное использование шаблонов. Компилятор не может выдать нормальное сообщение об ошибке (тому есть простое техническое обоснование, но оно приемлемо только для разработчиков компиляторов, а не для начинающих программистов).

Метапрограммирование на C++ (часто употребляется термин обобщенное программирование, подразумевая, что, к примеру, написанный обобщенный алгоритм может компилироваться с разными типами аргументов) опирается на механизм шаблонов C++. Можно посмотреть на библиотеку Boost C++ - такие средства обобщенного программирования, как выбор наиболее подходящего типа для объявления аргумента функции (Boost.Call_Traitsи многие другие целиком опираются на этот механизм. Для понимания многих моментов крайне желательно хотя бы шапочно познакомиться с принципами построения функциональных языков (к примеру Лисп, Haskell - см. здесь), иначе будет трудно разобраться, каким образом выполняются настоящие вычисления (см. ниже) без применения циклов и присваиваний (в шаблонном программировании доступны только рекурсия, условный выбор и однократное присваивание через объявление enum в классе).

Любопытную статью о метапрограммировании можно почитать на RSDN.

 

Примеры метапрограммирования

обобщенное программирование в C++ базируется на шаблонах

Шаблоны C++. Справочник разработчика: подробнее

Дэвид Вандевурд, Николаи М. Джосаттис
Шаблоны C++. Справочник разработчика

13.04.2005 Вычисление факториала на стадии компиляции

15.05.2005 Проверка условия на стадии компиляции

15.05.2005 Выбор кода при компиляции (compile time switch) - применение шаблонного класса Int2Type из библиотеки Loki.

16.04.2005 Целочисленные типы заданного размера в библиотеке BOOST C++

16.04.2005 Использование System::Reflection в .NET для создания плагинов

14.06.2005 Генератор отчетов БД с элементами метаязыка - программа (с исходными текстами), которая совмещает в себе функциональность препроцессора и интерпретатора простого языка, позволяя писать самомодифицирующиеся программы с практическим применением - генерацией HTML отчетов для баз данных.

12.06.2005 Списки типов (typelists) - реализация на стандартном C++ в библиотеке Loki.

 

 

последние изменения 14.06.2005

  © Mental Computing 2010