Estoy tratando de entender qué metaprogramación es general y qué es en C ++ en particular
No has dicho lo que entiendes por metaprogramación en general , por lo que sus respuestas no tienen un punto de partida común.
Voy a asumir la definición de Wikipedia es lo suficientemente bueno para esto:
La metaprogramación es una técnica de programación en la que los programas de computadora tienen la capacidad de tratar a otros programas como sus datos.
... se puede usar para mover cálculos del tiempo de ejecución al tiempo de compilación, para generar código usando cálculos de tiempo de compilación ...
C ++ generalmente no permite código auto modificable, así que lo estoy ignorando. También elijo no contar el preprocesador, ya que la sustitución textual en (o posiblemente justo antes) del tiempo de compilación no es lo mismo que operar en la semántica del programa.
Mi pregunta es si todos los usos de plantillas en C ++ se clasifican como metaprogramación
No, no es.
Considere, como referencia:
#define MAX(a,b) ((a) > (b) ? (a) : (b))
que es la forma más amplia de escribir un genérico (independiente del tipo) max
sin usar plantillas. Ya he dicho que no cuento el preprocesador como metaprogramación, pero en cualquier caso siempre produce un código idéntico cada vez que se usa.
Simplemente delega el análisis de ese código y se preocupa por los tipos y si a>b
está definido para el compilador, en una fase de traducción posterior . Nada aquí opera en tiempo de compilación para producir un código resultante diferente dependiendo de ... cualquier cosa. Nada, en tiempo de compilación, se calcula.
Ahora, podemos comparar la versión de la plantilla:
template <typename T>
T max(T a, T b) { return a > b ? a : b; }
Esto no solo realiza una sustitución textual. El proceso de creación de instancias es más complejo, se pueden considerar reglas de búsqueda de nombres y sobrecargas, y en cierto sentido diferentes instancias pueden no ser equivalentes textualmente (por ejemplo, uno puede usar bool ::operator< (T,T)
y otrobool T::operator<(T const&)
o lo que sea).
Sin embargo, el significado de cada instanciación es el mismo (suponiendo definiciones compatibles deoperator<
diferentes tipos, etc.) y no se calculó nada en el momento de la compilación, aparte del proceso habitual (mecánico) del compilador de resolver tipos y nombres, etc.
Por otro lado, definitivamente no es suficiente que su programa contenga instrucciones para que el compilador le diga qué hacer , porque eso es toda la programación.
Ahora, hay casos marginales como
template <unsigned N>
struct factorial() { enum { value = N * factorial<N-1>::value }; };
el cual hacer avanzar un cálculo de tiempo de compilación (y en este caso un no-terminación de uno ya que no puedo ser molestado a escribir el caso de terminales), pero podría decirse que están no metaprogramming.
Aunque la definición de Wikipedia menciona los cálculos en movimiento para compilar el tiempo, esto es solo un cálculo de valor, no es una decisión en tiempo de compilación sobre la estructura o la semántica de su código.