C++

индекс
236,50

DSL для boost::MPL, превращаем f(x) в f<x>::type

Краткое содержание статьи (для тех кто знаком с boost::mpl), typename опущены для ясности:
a = b;				==>		typedef b a;
f(x)				==>		f<x>::type
f(x) { return x*; }		==>		template<typename x> struct x { typedef x* type; };
f()(x)				==>		f::apply<x>::type
a[x]				==>		mpl::at<a, x>::type
(x ? y : z)			==>		mpl::if_<x, y, z>::type
switch (if_<x, y, z>)		==>		*Уфф*, общая (default) и частичные специализации
{
	case if_<bool_<false>, y, z>: return y;
	default: return z;
}

Под хабракатом есть немного пояснений :)

Если кто не в курсе, в С++ есть некоторый, слегка искусственный, механизм, позволяющий выполнять преобразования типов.
Есть у нас обычная переменная x, применяем к ней функцию f(x) и получаем другую переменную.
Так вот, и с типами можно похоже поступать — с помощью механизма шаблонов можно применять к некоторому типу x метафункцию f — «вызов» выполняется так: f<x>::type.
А метафункцию f описывают шаблонной структурой:
template<typename x>
struct f
{
	typedef x* type;
};


Конкретно эта метафункция превращает тип в указатель на этот тип.
В общем, бустовская библиотека MPL — это такая весьма мощная штука, позволяющая оперировать с контейнерами типов, применять к ним метафункторы и т.д. (все на этапе компиляции, естественно).
Мощная она, конечно, мощная, но голову там поломать на очередном
typedef typename detail::static_find_if<next_type, last_type, 
	mpl::bind1<typename mpl::lambda<pred_type>::type, 
		mpl::bind1<mpl::quote1<result_of::value_of>,mpl::_1>
		>
	> filter;

можно запросто.

Почему бы не сделать для этого DSL, т.е. специальный язык препроцессора, превращающий
__dsl::mpl { a = f(x); } в typedef typename f<x>::type a;?

А __dsl::mpl{ f(x) { return x*; } } — в ту самую шаблонную структуру.

Т.е. с помощью __dsl::mpl{...} мы говорим «вот в этом блоке кода мы будем заниматься метапрограммированием». И занимаемся. А вызов функции превращается в вызов метафункции, присваивание превращается в typedef и т.д.

Да, дополнительная стадия компиляции, ну а куда деваться? В чистом виде люди этого mpl'я просто боятся :).

В общем, за 1 день с помощью boost::spirit 2 удалось реализовать почти все описанные в заголовке конструкции.
Основное правило преобразования простое — все что во входном потоке не __dsl::mpl{… } отправляем на выход, что внутри нашего блока — транслируем.
Думаю, еще списки инициализации надо добавить, чтобы писать:
vector my_types = { MainWindow, AboutWindow, ExitWindow };

P.S. Может, кто подскажет, как такое потеснее заинтегрировать в Visual Studio? Чтобы не создавать дополнительные файлы и номера строк для ошибок отображать. Эх, мечты, мечты.
+17
7 марта 2010, 09:41
14

комментарии (14)

0
Paul #
Может, кто подскажет, как такое потеснее заинтегрировать в Visual Studio? Чтобы не создавать дополнительные файлы и номера строк для ошибок отображать.
Можно попробовать написать прокси-cl.exe, который будет транслировать __dsl::, а потом вызывать настоящий cl.exe. Так вроде бы STLFilt работает.
0
AndrewAZ #
Просто если уж подобную штуку использовать, то можно сразу на разные подпути повесить разные вспомогательные dsl, типа описания файлового формата или еще чего. Но для использования он должен как-то автоматом настраиваться у всех в компании.
Покопаю в сторону прокси-cl.exe, но вообще думал, может есть в студии подключаемые препроцессоры.
0
kolobog007 #
в настройках проекта есть pre-build event, способный вызывать стороннюю программу. может поможет.
0
bga #
тем временем рождается новая эволюция С с типом auto вложенными функциями, foreach и другими вкусностями
trac.assembla.com/SuperCalc/browser
trac.assembla.com/SuperCalc/export/662/LanguageEN.html
+2
Volfram #
*Нет, я не должен этого говорить, нет, я не должен… аргх!*
D?
0
Filippok #
нет, NULLC!
+1
tass #
Вот уж вложенные функции это точно не вкусности, а лишнее запутывание архитектуры. Нафига оно нужно то?
0
mefix #
Для лямбд и замыканий.
0
tass #
а, вы в этом смысле вложенные функции. Я то думал как в паскале было.
0
GooRoo #
Для того чтобы интегрировать в вижуал, я вижу два пути:

1) настраивать каждый раз вручную для проекта Pre-Build Events (собственно препроцессинг) и Post-Build Events (зачистка сгенерированных файлов). Впрочем, есть способ немного упростить процесс настройки, но всё равно будет не очень удобно.

2) писать код с кусками метапрограммирования в файлах с другим расширением. Тогда можно попробовать заюзать такую штуку как Custom Build Rules.

А отображение ошибок сделать проще простого. В MSDN описан формат, в котором кастомные тулзы должны выдавать ошибки и предупреждения. Если его придерживаться, то ошибки будут отображаться в окне Errors, а двойной клик на ошибку перебросит на нужную строку. Я так doxygen прикручивал когда-то.

P.S. Сорри, что без скринов. У меня вижуал на русском :)
0
bashor #
В студии есть Property Menager, который позволяет сохранять настройки хранить в отдельном файле, можно даже «наследовать».
0
GooRoo #
Да, я знаю. Как раз попытался об этом написать.
–1
Finderom #
Я кликнул по заголовку только для того чтобы узнать о чем этот заголовок.
+1
San13 #
Greenspun's Tenth Rule:
Аny sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp.

""«Любая достаточно сложная Ц или Фортран программа содержит по-быстренькому написанную нестандартную глючную медленную реализацию половины языка Lisp.»""

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.