Pregunta

¿Cuáles son los mejores ejemplos de metaprogramación que has visto en C ++?
¿Cuáles son algunos usos prácticos de la metaprogramación que has visto en C ++?

¿Fue útil?

Solución

Personalmente, creo que Boost.Spirit es un ejemplo bastante sorprendente de metaprogramación. Es un generador de analizador completo que le permite expresar gramáticas utilizando la sintaxis de C ++.

Otros consejos

El uso más práctico de la meta programación es convertir un error de tiempo de ejecución en un error de tiempo de compilación.

Ejemplo: Llamemos a la interfaz IFoo. Uno de mis programas trataba con un objeto COM que tenía múltiples rutas a IFoo (jerarquía de herencia muy complicada). Desafortunadamente, la implementación del objeto COM subyacente no se dio cuenta de que tenían múltiples rutas a IFoo. Asumieron que siempre era el más a la izquierda. Entonces, dentro de su código, el siguiente patrón era muy común

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

El segundo IFoo causó el resultado " p " el puntero es completamente inválido (la herencia múltiple es peligrosa).

La solución a largo plazo fue hacer que el propietario del objeto COM solucione este problema. A corto plazo, aunque necesitaba asegurarme de que siempre devolvía el IFoo correcto. Podría garantizar que tenía el IFoo apropiado usando un QI y evitando cualquier conversión implícita a IFoo. Así que creé un nuevo CComPtr & Lt; & Gt; implementación y agregó la siguiente anulación al método de igualdad.

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

Esto reveló rápidamente todos los lugares que implícitamente lancé a IFoo.

No es de uso práctico (excepto tal vez para la prueba del compilador), pero metatrace es un estilo Whitted (es decir, recursivo y determinista) trazador de rayos que genera imágenes como las del momento de la compilación:

ejemplo de metatrace

Algunas partes más complejas del código se pueden ver en fixp.hh , que tiene una implementación de sqrt de punto fijo usando Heron método, o sphere.hh que muestra la intersección rayo / esfera cálculo.

Blitz ++ hace algunas cosas impresionantes con las plantillas (por ejemplo, una sola línea de código legible puede ser convertido en un conjunto de bucles sobre una matriz multidimensional, optimizado automáticamente para el mejor orden transversal).

El mejor ejemplo de metaprogramación: engañando al compilador para que calcule una lista de números primos. No muy práctico, pero impresionante.

Un uso práctico son las declaraciones de afirmación en tiempo de compilación, es decir, causar un error de compilación si no se cumple una condición booleana.

Tendría que decir Boost.Lambda, Boost.Function y Boost.Bind y la forma en que todos funcionan a la perfección juntos. Proporcionan una interfaz muy ingeniosa y hacen que la programación funcional sea lo más fácil posible en un lenguaje que realmente no fue creado para ello.

luabind es un ejemplo práctico bastante bueno, un buen enlace dsl para vincular clases de C ++ a lua

BOOST_FOREACH

Aserción estática (aumenta la versión aquí )

(Nota: en C ++ 11 se introduce compatibilidad integrada para el rango basado en bucles y aserciones estáticas)

Planteé una pregunta no hace mucho: C ++ Runtime Knowledge of Classes y la respuesta que recibí de un usuario de StackOverflow & Quot; Denice & Quot; era una URL de un sitio web Meatspace: C ++ runtime registro de clase .

Creo que es una forma realmente genial de usar plantillas e instanciar objetos que se derivan de una clase base, de modo que cuando tengo 10 archivos C ++, todos pueden agregar AUTO_REGISTER_BASE () en la parte inferior, y cuando todo está hecho y vinculado, solo aquellas clases / archivos que lo hicieron estarían registrados, por lo que en tiempo de ejecución puede cambiar entre las diferentes clases que están disponibles, y las que no están disponibles no están registradas y, por lo tanto, no se pueden llamar accidentalmente .

Hay muchas formas diferentes de sistema operativo para hacer notificaciones de eventos (select (), kqueue (), / dev / epoll, Solaris tiene su propia cosa, poll ()), y necesitaba una forma de tener toda la clase existen archivos en el directorio, pero dependiendo de qué sistema operativo se ejecutó el Makefile, solo compilaría ciertos. Necesitaba una forma de saber en tiempo de ejecución cuáles estaban disponibles, y tener una forma para que el programador que usa la biblioteca seleccione su preferencia, sin embargo, si no estaba disponible, simplemente usa la que tenía el sentido más lógico para la plataforma (cada uno tener pesos asignados a ellos).

¡El código anterior me ayudó a lograr este objetivo, con algunas modificaciones importantes, pero de todos modos me ayudó!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top