Краткое содержание статьи (для тех кто знаком с boost::mpl), typename опущены для ясности:
Под хабракатом есть немного пояснений :)
Если кто не в курсе, в С++ есть некоторый, слегка искусственный, механизм, позволяющий выполнять преобразования типов.
Есть у нас обычная переменная x, применяем к ней функцию f(x) и получаем другую переменную.
Так вот, и с типами можно похоже поступать — с помощью механизма шаблонов можно применять к некоторому типу x метафункцию f — «вызов» выполняется так:
А метафункцию f описывают шаблонной структурой:
Конкретно эта метафункция превращает тип в указатель на этот тип.
В общем, бустовская библиотека MPL — это такая весьма мощная штука, позволяющая оперировать с контейнерами типов, применять к ним метафункторы и т.д. (все на этапе компиляции, естественно).
Мощная она, конечно, мощная, но голову там поломать на очередном
можно запросто.
Почему бы не сделать для этого DSL, т.е. специальный язык препроцессора, превращающий
А
Т.е. с помощью __dsl::mpl{...} мы говорим «вот в этом блоке кода мы будем заниматься метапрограммированием». И занимаемся. А вызов функции превращается в вызов метафункции, присваивание превращается в typedef и т.д.
Да, дополнительная стадия компиляции, ну а куда деваться? В чистом виде люди этого mpl'я просто боятся :).
В общем, за 1 день с помощью boost::spirit 2 удалось реализовать почти все описанные в заголовке конструкции.
Основное правило преобразования простое — все что во входном потоке не __dsl::mpl{… } отправляем на выход, что внутри нашего блока — транслируем.
Думаю, еще списки инициализации надо добавить, чтобы писать:
vector my_types = { MainWindow, AboutWindow, ExitWindow };
P.S. Может, кто подскажет, как такое потеснее заинтегрировать в Visual Studio? Чтобы не создавать дополнительные файлы и номера строк для ошибок отображать. Эх, мечты, мечты.
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? Чтобы не создавать дополнительные файлы и номера строк для ошибок отображать. Эх, мечты, мечты.