Ejemplo
#include <iostream>
template <int N> struct Factorial
{
enum { val = Factorial<N-1>::val * N };
};
template<>
struct Factorial<0>
{
enum { val = 1 };
};
int main()
{
// Note this value is generated at compile time.
// Also note that most compilers have a limit on the depth of the recursion available.
std::cout << Factorial<4>::val << "\n";
}
Eso fue un poco divertido pero no muy práctico.
Para responder a la segunda parte de la pregunta:
¿Es este hecho útil en la práctica?
Respuesta corta: algo así.
Respuesta larga: Sí, pero solo si es un demonio de plantilla.
Producir una buena programación utilizando metaprogramación de plantillas que sea realmente útil para que otros la usen (es decir, una biblioteca) es realmente difícil (aunque factible). Para ayudar a impulsar, incluso tiene MPL también conocido como (Meta biblioteca de programación). Pero intente depurar un error del compilador en el código de su plantilla y le espera un viaje largo y duro.
Pero un buen ejemplo práctico de cómo se usa para algo útil:
Scott Meyers ha estado trabajando en extensiones del lenguaje C ++ (uso el término libremente) usando las facilidades de plantillas. Puede leer sobre su trabajo aquí ' Aplicación de funciones de código '
Hice una máquina de turing en C ++ 11. Las características que agrega C ++ 11 no son significativas para la máquina de turing. Solo proporciona listas de reglas de longitud arbitraria usando plantillas variadas, en lugar de usar metaprogramación macro perversa :). Los nombres de las condiciones se utilizan para generar un diagrama en stdout. He eliminado ese código para que la muestra sea breve.
fuente
" C ++ Templates Are Turing Complete " ofrece una implementación de una máquina de Turing en plantillas ... que no es trivial y demuestra el punto de una manera muy directa. ¡Por supuesto, tampoco es muy útil!
fuente
Mi C ++ está un poco oxidado, por lo que puede que no sea perfecto, pero está cerca.
El punto es demostrar que el compilador está evaluando completamente la definición recursiva hasta que llega a una respuesta.
fuente
Para dar un ejemplo no trivial: http://gitorious.org/metatrace , un trazador de rayos de tiempo de compilación de C ++.
Tenga en cuenta que C ++ 0x agregará una función de turing completa, en tiempo de compilación y sin plantilla en forma de
constexpr
:Puede usar
constexpr
-expression en cualquier lugar donde necesite compilar constantes de tiempo, pero también puede llamar aconstexpr
-functions con parámetros no constantes.Una cosa interesante es que esto finalmente permitirá la matemática de punto flotante en tiempo de compilación, aunque el estándar establece explícitamente que la aritmética de punto flotante en tiempo de compilación no tiene que coincidir con la aritmética de punto flotante en tiempo de ejecución:
fuente
The Book Modern C ++ Design - Generic Programming and Design Pattern de Andrei Alexandrescu es el mejor lugar para adquirir experiencia práctica con patrones de programación genéricos útiles y poderosos.
fuente
El ejemplo factorial en realidad no muestra que las plantillas estén completas en Turing, tanto como muestra que admiten la recursividad primitiva. La forma más fácil de demostrar que las plantillas se están completando es mediante la tesis de Church-Turing, es decir, implementando una máquina de Turing (desordenada y un poco inútil) o las tres reglas (aplicación, abs var) del cálculo lambda sin tipo. Este último es mucho más simple y mucho más interesante.
Lo que se está discutiendo es una característica extremadamente útil cuando se comprende que las plantillas C ++ permiten una programación funcional pura en tiempo de compilación, un formalismo que es expresivo, poderoso y elegante pero también muy complicado de escribir si se tiene poca experiencia. Observe también cuántas personas encuentran que solo obtener código con muchas plantillas a menudo puede requerir un gran esfuerzo: este es exactamente el caso de los lenguajes funcionales (puros), que hacen que la compilación sea más difícil, pero sorprendentemente produce código que no requiere depuración.
fuente
Creo que se llama metaprogramación de plantillas .
fuente
Bueno, aquí hay una implementación de Turing Machine en tiempo de compilación que ejecuta un castor ocupado de 4 estados y 2 símbolos
Prueba de ejecución de Ideone: https://ideone.com/MvBU3Z
Explicación: http://victorkomarov.blogspot.ru/2016/03/compile-time-turing-machine.html
Github con más ejemplos: https://github.com/fnz/CTTM
fuente
Puede consultar este artículo del Dr. Dobbs sobre una implementación de FFT con plantillas que no creo que sean tan triviales. El punto principal es permitir que el compilador realice una mejor optimización que para las implementaciones sin plantilla, ya que el algoritmo FFT utiliza muchas constantes (tablas sin, por ejemplo)
parte I
Parte II
fuente
También es divertido señalar que es un lenguaje puramente funcional, aunque casi imposible de depurar. Si miras la publicación de James , verás lo que quiero decir con que es funcional. En general, no es la característica más útil de C ++. No fue diseñado para hacer esto. Es algo que se descubrió.
fuente
Puede resultar útil si desea calcular constantes en tiempo de compilación, al menos en teoría. Consulte la metaprogramación de plantillas .
fuente
Un ejemplo que es razonablemente útil es una clase de razón. Hay algunas variantes flotando. Detectar el caso D == 0 es bastante simple con sobrecargas parciales. La computación real está en calcular el MCD de N y D y el tiempo de compilación. Esto es esencial cuando utiliza estas proporciones en cálculos en tiempo de compilación.
Ejemplo: cuando calcula centímetros (5) * kilómetros (5), en el momento de la compilación, multiplicará la relación <1,100> y la relación <1000,1>. Para evitar el desbordamiento, desea una proporción <10,1> en lugar de una proporción <1000,100>.
fuente
Una máquina de Turing es Turing completa, pero eso no significa que deba utilizar una para el código de producción.
En mi experiencia, intentar hacer algo que no sea trivial con las plantillas es desordenado, feo y sin sentido. No tiene forma de "depurar" su "código", los mensajes de error en tiempo de compilación serán crípticos y generalmente en los lugares más improbables, y puede lograr los mismos beneficios de rendimiento de diferentes maneras. (Pista: 4! = 24). Peor aún, su código es incomprensible para el programador promedio de C ++ y probablemente no será portátil debido a los amplios niveles de soporte dentro de los compiladores actuales.
Las plantillas son excelentes para la generación de código genérico (clases de contenedor, envoltorios de clases, combinaciones), pero no, en mi opinión, la integridad de Turing de las plantillas NO ES ÚTIL en la práctica.
fuente
Solo otro ejemplo de cómo no programar:
Publicar en C ++ las plantillas se están completando
fuente
K17<Depth+1>::x * 5
.