Exemplo
#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";
}
Foi um pouco divertido, mas não muito prático.
Para responder à segunda parte da pergunta:
esse fato é útil na prática?
Resposta curta: mais ou menos.
Resposta longa: Sim, mas apenas se você for um daemon de modelo.
Para produzir uma boa programação usando meta-programação de modelo que seja realmente útil para outros usarem (ou seja, uma biblioteca) é realmente muito difícil (embora capaz de fazer). Para ajudar a impulsionar ainda tem MPL aka (Biblioteca de Metaprogramação). Mas tente depurar um erro do compilador em seu código de modelo e você terá uma longa jornada difícil.
Mas um bom exemplo prático de como isso é usado para algo útil:
Scott Meyers tem trabalhado com extensões para a linguagem C ++ (uso o termo vagamente) usando os recursos de modelagem. Você pode ler sobre o trabalho dele aqui ' Aplicando recursos do código '
Eu fiz uma máquina turing em C ++ 11. Os recursos que C ++ 11 adiciona não são significativos para a máquina de turing de fato. Ele apenas fornece listas de regras de comprimento arbitrário usando modelos variadic, em vez de usar metaprogramação de macro perversa :). Os nomes das condições são usados para gerar um diagrama em stdout. Eu removi esse código para manter a amostra curta.
fonte
" C ++ Templates Are Turing Complete " fornece uma implementação de uma máquina de Turing em templates ... o que não é trivial e prova isso de uma maneira muito direta. Claro, também não é muito útil!
fonte
Meu C ++ está um pouco enferrujado, então pode não ser perfeito, mas está perto.
O objetivo é demonstrar que o compilador está avaliando completamente a definição recursiva até chegar a uma resposta.
fonte
Para dar um exemplo não trivial: http://gitorious.org/metatrace , um ray tracer de tempo de compilação C ++.
Observe que C ++ 0x adicionará um recurso não-template, em tempo de compilação e turing-complete na forma de
constexpr
:Você pode usar
constexpr
-expression em todos os lugares onde precisar de constantes de tempo de compilação, mas também pode chamarconstexpr
-functions com parâmetros não constantes.Uma coisa legal é que isso finalmente habilitará a matemática de ponto flutuante em tempo de compilação, embora o padrão afirme explicitamente que a aritmética de ponto flutuante em tempo de compilação não precisa corresponder à aritmética de ponto flutuante em tempo de execução:
fonte
O livro Modern C ++ Design - Generic Programming and Design Pattern de Andrei Alexandrescu é o melhor lugar para obter experiência prática com padrões de programação genéricos úteis e poderosos.
fonte
O exemplo fatorial, na verdade, não mostra que os modelos são Turing completos, mas mostra que eles suportam a recursão primitiva. A maneira mais fácil de mostrar que os modelos estão se tornando completos é pela tese de Church-Turing, isto é, implementando uma máquina de Turing (bagunçada e um pouco sem sentido) ou as três regras (app, abs var) do cálculo lambda não tipado. O último é muito mais simples e muito mais interessante.
O que está sendo discutido é um recurso extremamente útil quando você entende que os modelos C ++ permitem programação funcional pura em tempo de compilação, um formalismo que é expressivo, poderoso e elegante, mas também muito complicado de escrever se você tiver pouca experiência. Observe também quantas pessoas descobrem que apenas obter código fortemente modelado pode muitas vezes exigir um grande esforço: este é exatamente o caso com linguagens funcionais (puras), que tornam a compilação mais difícil, mas surpreendentemente produz código que não requer depuração.
fonte
Acho que é chamado de meta-programação de modelo .
fonte
Bem, aqui está uma implementação de máquina de Turing em tempo de compilação executando um castor ocupado de 4 estados e 2 símbolos
Prova de execução Ideone: https://ideone.com/MvBU3Z
Explicação: http://victorkomarov.blogspot.ru/2016/03/compile-time-turing-machine.html
Github com mais exemplos: https://github.com/fnz/CTTM
fonte
Você pode verificar este artigo do Dr. Dobbs sobre uma implementação de FFT com modelos que não acho tão triviais. O ponto principal é permitir que o compilador execute uma otimização melhor do que para implementações sem modelo, já que o algoritmo FFT usa muitas constantes (tabelas sin, por exemplo)
parte eu
parte II
fonte
Também é divertido apontar que é uma linguagem puramente funcional, embora quase impossível de depurar. Se você olhar a postagem de James , verá o que quero dizer com ser funcional. Em geral, não é o recurso mais útil do C ++. Não foi projetado para fazer isso. É algo que foi descoberto.
fonte
Pode ser útil se você quiser calcular constantes em tempo de compilação, pelo menos em teoria. Confira a metaprogramação de template .
fonte
Um exemplo razoavelmente útil é uma classe de razão. Existem algumas variantes flutuando. Pegar o caso D == 0 é bastante simples com sobrecargas parciais. A computação real está no cálculo do GCD de N e D e no tempo de compilação. Isso é essencial quando você usa essas proporções em cálculos em tempo de compilação.
Exemplo: Ao calcular centímetros (5) * quilômetros (5), no momento da compilação, você estará multiplicando a proporção <1.100> e a proporção <1000,1>. Para evitar estouro, você deseja uma proporção <10,1> em vez de uma proporção <1000,100>.
fonte
Uma máquina de Turing é Turing-completa, mas isso não significa que você deva usar uma para o código de produção.
Tentar fazer algo não trivial com modelos é, em minha experiência, confuso, feio e sem sentido. Você não tem como "depurar" seu "código", as mensagens de erro em tempo de compilação serão enigmáticas e geralmente nos lugares mais improváveis, e você pode obter os mesmos benefícios de desempenho de maneiras diferentes. (Dica: 4! = 24). Pior, seu código é incompreensível para o programador C ++ comum e provavelmente não será portável devido aos diversos níveis de suporte nos compiladores atuais.
Os modelos são ótimos para geração de código genérico (classes de contêiner, wrappers de classe, mix-ins), mas não - na minha opinião, a Completude Turing dos modelos NÃO É ÚTIL na prática.
fonte
Apenas outro exemplo de como não programar:
Postagem em modelos C ++ estão se tornando completos
fonte
K17<Depth+1>::x * 5
.