Какие самые крутые примеры метапрограммирования вы видели в C++?

Какие самые крутые примеры метапрограммирования вы видели в C++?
Какие практические применения метапрограммирования вы видели в C++?


person Brian R. Bondy    schedule 26.10.2008    source источник
comment
Я думаю, что Boost Metaparse — это действительно замечательная вещь github.com/boostorg/metaparse github.com/sabel83/metaparse_tutorial   -  person Jerry Jeremiah    schedule 12.10.2016


Ответы (10)


Лично я думаю, что Boost.Spirit — довольно удивительный пример метапрограммирования. Это полный генератор синтаксического анализатора, который позволяет вам выражать грамматики с использованием синтаксиса C++.

person Ferruccio    schedule 26.10.2008
comment
+1: дух довольно болен. Возможно, вы захотите дать ссылку на более новую версию духа? Эта версия кажется немного старой. - person n1ckp; 27.10.2010
comment
@n1ck: спасибо, я обновил ссылку - person Ferruccio; 27.10.2010

Наиболее практичным применением метапрограммирования является превращение ошибки времени выполнения в ошибку времени компиляции.

Пример: позвоним интерфейсу IFoo. Одна из моих программ работала с COM-объектом, у которого было несколько путей к IFoo (очень сложная иерархия наследования). К сожалению, базовая реализация COM-объекта не понимала, что у них есть несколько путей к IFoo. Они предполагали, что это всегда был самый левый. Итак, внутри их кода очень часто встречался следующий шаблон

   void SomeMethod(IFoo* pFoo) {
        CFooImpl *p = (CFooImpl)pFoo;
   }

Однако второй IFoo привел к тому, что результирующий указатель «p» стал полностью недействительным (множественное наследование опасно).

Долгосрочное решение заключалось в том, чтобы владелец COM-объекта исправил эту проблему. В краткосрочной перспективе мне нужно было убедиться, что я всегда возвращал правильный IFoo. Я мог гарантировать, что у меня есть соответствующий IFoo, используя QI и избегая любых неявных приведений к IFoo. Поэтому я создал новую реализацию CComPtr‹> и добавил следующее переопределение в метод equal.

template <typename T>
CComPtr<T>& operator=(const T* pT)  { 
// CComPTr Assign logic
}
template <>
CComPtr<IFoo> operator=<IFoo>(const IFoo* pT) {
  COMPILE_ERROR();
}

Это быстро выявило каждое место, которое я неявно привёл к IFoo.

person JaredPar    schedule 26.10.2008
comment
QI = QueryInterface msdn.microsoft.com/en-us/ библиотека/ms682521(VS.85).aspx - person JaredPar; 26.10.2008
comment
Это метапрограммирование? Вроде простая специализация. - person fizzer; 26.10.2008
comment
Во многих отношениях метапрограммирование является специализацией. Это довольно простой пример метапрограммирования (но очень эффективный). Я думаю, что это представляет собой один из наиболее практичных аспектов метапрограммирования, предохраняя вас от причинения вреда себе. - person JaredPar; 26.10.2008
comment
Я думаю, это грандиозно называть это метапрограммированием. Я не вижу выбора, рекурсии или любых других конструкций программирования времени компиляции. - person fizzer; 26.10.2008
comment
Это действительно умное мышление - потрясающе! - person JBRWilkinson; 18.02.2010

Не имеет практического применения (за исключением, возможно, тестирования компилятора), но metatrace является стилем Уиттеда (т.е. рекурсивным и детерминированным) трассировщик лучей, который генерирует подобные изображения во время компиляции:

пример метатрассировки

Некоторые более сложные части кода можно увидеть в fixp.hh, в котором реализована реализация sqrt с фиксированной точкой с использованием метода Heron, или sphere.hh, который показывает расчет пересечения луча/сферы.

person Sebastian Mach    schedule 26.07.2011

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

person CesarB    schedule 26.10.2008
comment
Ух ты. Я понимаю, что это немного поздно, но если у вас есть возможность указать на рассматриваемую строку, это было бы здорово. - person Praxeolitic; 05.03.2014
comment
Ссылка вроде изменена - person TankorSmash; 29.10.2017

Самый крутой пример метапрограммирования: заставить компилятор вычислить список простых чисел. Не очень практично, но впечатляюще.

Одним из практических применений являются операторы assert во время компиляции, т. е. вызывающие ошибку компиляции, если логическое условие не выполняется.

person John D. Cook    schedule 26.10.2008

Локи автор Андрей Александреску

person Community    schedule 26.10.2008

Я бы сказал Boost.Lambda, Boost.Function и Boost.Bind и то, как они все работают без проблем вместе. Они обеспечивают действительно приятный интерфейс и максимально упрощают функциональное программирование на языке, который на самом деле не был создан для этого.

person user21714    schedule 26.10.2008
comment
Теперь все они нативные в С++ 11. - person TankorSmash; 29.10.2017

luabind — довольно классный практический пример, неплохой связующий dsl для привязки классов C++ к lua.

person Keith Nicholas    schedule 26.10.2008

BOOST_FOREACH

Статическое утверждение (ускоряет версию здесь)

(Примечание: встроенная поддержка циклов for на основе диапазона и статических утверждений введена в C++11)

person Viktor Sehr    schedule 26.10.2010

Недавно я задал вопрос: Классы, и ответ, который я получил от пользователя StackOverflow "Denice", был URL-адресом веб-сайта Meatspace: регистрация класса среды выполнения C++.

Я думаю, что это действительно классный способ использовать шаблоны и создавать экземпляры объектов, которые все являются производными от базового класса, так что, когда у меня есть 10 файлов C++, все они могут просто добавить AUTO_REGISTER_BASE() внизу, а когда все готово сделано и связано, будут зарегистрированы только те классы/файлы, которые сделали это, поэтому во время выполнения вы можете переключаться между различными доступными классами, а те, которые недоступны, не регистрируются и, следовательно, не могут быть вызваны случайно.

Существует множество различных способов, зависящих от ОС, для уведомления о событиях (select(), kqueue(), /dev/epoll, в Solaris есть своя функция, poll()), и мне нужен был способ, чтобы все файлы классов существовали в каталог, но в зависимости от того, в какой ОС запускался Makefile, он компилировал только определенные файлы. Мне нужен был способ узнать во время выполнения, какие из них доступны, и иметь возможность для программиста, использующего библиотеку, выбрать свои предпочтения, однако, если это было недоступно, просто использовать тот, который имел наиболее логичный смысл для платформы (каждый из них им присвоены веса).

Приведенный выше код помог мне достичь этой цели с некоторыми значительными изменениями, но, тем не менее, он помог мне!

person X-Istence    schedule 26.10.2008