2011-04-16 21 views
65

Entiendo que el parámetro de plantilla sin tipo debe ser una expresión integral constante. ¿Alguien puede arrojar luz por qué es así?Parámetros de plantilla sin tipo

template <std::string temp> 
void foo() 
{ 
    // ... 
} 
error C2993: 'std::string' : illegal type for non-type template parameter 'temp'. 

entiendo lo que es una expresión integral constante es. ¿Cuáles son las razones para no permitir tipos no constantes como std::string como en el fragmento de arriba?

+14

Un parámetro de plantilla se resuelve en tiempo de compilación. –

Respuesta

93

La razón por la que no se puede hacer esto es porque las expresiones no constantes no se pueden analizar y sustituir durante el tiempo de compilación. Podrían cambiar durante el tiempo de ejecución, lo que requeriría la generación de una nueva plantilla durante el tiempo de ejecución, lo que no es posible porque las plantillas son un concepto en tiempo de compilación.

Aquí es lo que el estándar permite parámetros de plantilla no de tipo (14.1 [temp.param] p4):

Una plantilla-parámetro no tipo tendrá una de las siguientes (opcionalmente cv-cualificada) tipos:

  • tipo integral o enumeración,
  • puntero a objeto o puntero a funcionar,
  • referencia lvalue a objeto o de referencia lvalue a función,
  • puntero al miembro,
  • std::nullptr_t.
+0

¿Qué pasa con el puntero a la función miembro? – ALOToverflow

+6

@ALOToverflow: que cae bajo "puntero al miembro". Es "puntero a la función de miembro" o "puntero a datos de miembro". – Xeo

+2

Vale la pena señalar que para el caso de punteros a objetos (o campos de instancia), los objetos deben tener una duración de almacenamiento estático y un enlace (preC++ 11 externo, interno o externo en C++ 11), de modo que los punteros a ellos se puede crear en tiempo de compilación. –

8

Un argumento de plantilla no tipo provisto dentro de una lista de argumentos de plantilla es una expresión cuyo valor puede ser determinado en tiempo de compilación. Tales argumentos deben ser:

expresiones constantes, direcciones de funciones u objetos con enlazado externo, o direcciones de clase estática miembros.

Además, los literales de cadena son objetos con enlace interno, por lo que no puede usarlos como argumentos de plantilla. No puedes usar un puntero global, tampoco. Los literales de punto flotante no están permitidos, dada la posibilidad obvia de errores de redondeo.

59

Eso no está permitido.

Sin embargo, esto está permitido:

template <std::string * temp> //pointer to object 
void f(); 

template <std::string & temp> //reference to object 
void g(); 

Ver §14.1/6,7,8 en C++ estándar (2003).


Ilustración:

template <std::string * temp> //pointer to object 
void f() 
{ 
    cout << *temp << endl; 
} 

template <std::string & temp> //reference to object 
void g() 
{ 
    cout << temp << endl; 
    temp += "...appended some string"; 
} 

std::string s; //must not be local as it must have external linkage! 

int main() { 
     s = "can assign values locally"; 
     f<&s>(); 
     g<s>(); 
     cout << s << endl; 
     return 0; 
} 

Salida:

can assign values locally 
can assign values locally 
can assign values locally...appended some string 
+3

Gracias por la referencia. – Mahesh

+1

@Mahesh: ver la edición. : D – Nawaz

+0

@Nawaz - ¿Cuál es la razón para no permitir el mismo concepto para las variables locales? No puedo pensar por una razón para no permitirlo. Gracias. – Mahesh

21

Tienes que ser capaz de destrozar argumentos de plantilla

template <std::string temp> 
void f() { 
// ... 
} 

f<"foo">(); 
f<"bar">(); // different function!? 

Ahora un impl necesitaría para llegar a una secuencia de caracteres única s para un std::string o, para el caso, cualquier otra clase arbitraria definida por el usuario, almacenando un valor particular, cuyo significado no es conocido por la implementación. Y, además, el valor de los objetos de clase arbitrarios no se puede calcular en tiempo de compilación.

Está previsto considerar permitir tipos de clase literales como tipos de parámetros de plantilla para post-C++ 0x, que se inicializan mediante expresiones constantes. Esos podrían ser mutilados si los miembros de los datos se mutilan recursivamente de acuerdo con sus valores (para las clases de base, por ejemplo, podemos aplicar cruce transversal de profundidad, de izquierda a derecha). Pero definitivamente no va a funcionar para clases arbitrarias.

Cuestiones relacionadas