Estou tentando entender o que é metaprogramação geral e o que é em C ++ em particular
Você ainda não disse o que entende por metaprogramação em geral , para que suas respostas não tenham um ponto de partida comum.
Vou assumir que a definição da Wikipedia é boa o suficiente para isso:
A metaprogramação é uma técnica de programação na qual os programas de computador podem tratar outros programas como dados.
... pode ser usado para mover cálculos de tempo de execução para tempo de compilação, para gerar código usando cálculos de tempo de compilação ...
O C ++ geralmente não permite código auto-modificável, então estou ignorando isso. Também estou optando por não contar o pré-processador, pois a substituição de texto no (ou provavelmente antes) tempo de compilação não é o mesmo que operar na semântica do programa.
Minha pergunta é se todos os usos de modelos em C ++ são categorizados como metaprogramação
Não não é.
Considere, para referência:
#define MAX(a,b) ((a) > (b) ? (a) : (b))
que é vagamente a maneira de escrever uma função genérica ( max
independente de tipo) sem usar modelos. Eu já disse que não conto o pré-processador como metaprogramação, mas, em qualquer caso, ele sempre produz código idêntico sempre que é usado.
Ele simplesmente delega a análise desse código e a preocupação com os tipos e se a>b
está definido para o compilador, em uma fase posterior da tradução . Nada aqui opera em tempo de compilação para produzir código resultante diferente dependendo de ... qualquer coisa. Nada, em tempo de compilação, é calculado.
Agora, podemos comparar a versão do modelo:
template <typename T>
T max(T a, T b) { return a > b ? a : b; }
Isso não realiza simplesmente uma substituição textual. O processo de instanciação é mais complexo, regras de sobrecarga de nomes e sobrecargas podem ser consideradas e, em certo sentido, instâncias diferentes podem não ser textualmente equivalentes (por exemplo, um pode ser usado bool ::operator< (T,T)
e um bool T::operator<(T const&)
ou o que for).
No entanto, o significado de cada instanciação é o mesmo (assumindo definições compatíveis operator<
para tipos diferentes etc.) e nada foi computado no tempo de compilação, exceto o processo (mecânico) usual do compilador de resolver tipos e nomes e assim por diante.
Como um aparte, definitivamente não é suficiente que seu programa contenha instruções para o compilador dizer o que fazer , porque é isso que é toda a programação.
Agora, existem casos marginais como
template <unsigned N>
struct factorial() { enum { value = N * factorial<N-1>::value }; };
que faz mover um cálculo de tempo de compilação (e neste caso, um não-encerramento uma vez que não pode ser incomodado para escrever o caso terminal), mas sem dúvida são não metaprogramming.
Mesmo que a definição da Wikipedia mencionasse mover cálculos para compilar tempo, isso é apenas um cálculo de valor - não está tomando uma decisão em tempo de compilação sobre a estrutura ou semântica do seu código.