vectores resueltos punteros matrices funciones ejercicios declaracion con aritmetica c++ pointers c++11 constant-expression

c++ - resueltos - ¿Por qué un puntero constante no puede ser una expresión constante?



punteros y matrices en c (3)

El siguiente programa compila:

template <const int * P> class Test{}; extern const int var = 42; //extern needed to force external linkage int main() { Test<&var> test; }

Este, sin embargo, no, lo cual es una sorpresa para mí:

template <const int * P> class Test{}; extern const int var = 42; //extern needed to force external linkage extern const int * const ptr = &var; //extern needed to force external linkage int main() { Test<ptr> test; //FAIL! Expected constant expression. }

Ejemplo alternativo:

int main() { const int size = 42; int ok[*&size]; //OK const int * const pSize = &size; int fail[*pSize]; //FAIL }

He llegado a la conclusión de que un puntero simplemente no puede ser una expresión constante independientemente de si es const o si se inicializa con una expresión constante.

Preguntas:

  1. ¿Es verdad mi conclusión?
  2. Si es así, ¿por qué un puntero no puede ser una expresión constante? Si no, ¿por qué los programas anteriores no se compilan?
  3. ¿C ++ 0x (C ++ 11, si se quiere) cambia algo?

Gracias por cualquier idea!


El problema se debe a que su programa C ++ se puede cargar en cualquier punto de la memoria, por lo que la dirección de una var global puede ser diferente cada vez que ejecuta el programa. ¿Qué sucede si ejecuta su programa dos veces? var es obviamente en dos lugares diferentes entonces.

Peor aún, en tu ejemplo, tomas la dirección de una variable en la pila. mira este:

void myfunction( unsigned int depth) { const int myvar = depth; const int * const myptr = &myvar; if (depth) myfunction(depth-1); }

Si la llamada principal es myfunction (3), entonces se crean 3 myvars en ubicaciones separadas. No hay forma de que el tiempo de compilación ni siquiera sepa cuántos myvars se crean, y mucho menos las ubicaciones exactas.

Finalmente: declarar que una variable es const significa: "Prometo", y no significa que sea una constante de tiempo de compilación. Mira este ejemplo:

int main(int argc, char** argv) { const int cargc = argc; char* myargs[cargc]; //the size is constant, but not a _compile time_ constant. }


Es un poco más complicado. En C ++ 03 y C ++ 11, &var es una expresión constante si var es una variable estática local / clase estática o de ámbito de espacio de nombres. Esto se llama una expresión constante de dirección. Se garantiza que la inicialización de una variable de puntero de ámbito estático o de espacio de nombre de clase con esa expresión constante se realizará antes de ejecutar cualquier código (fase de inicialización estática), debido a que es una expresión constante.

Sin embargo, solo en C ++ 11, una variable de puntero constexpr que almacena la dirección &var también se puede usar como expresión de dirección constante y solo en C ++ 11, puede desreferenciar una expresión constante de dirección (en realidad, puede desviar la referencia aún más) incluso direcciones de elemento de matriz local, pero mantengamos ontópico) y si se refiere a una variable integral constante inicializada antes de la desreferencia o una variable constexpr, de nuevo se obtiene una expresión constante (dependiendo del tipo y categoría de valor, el tipo de constante) la expresión puede variar). Como tal, el siguiente es válido C ++ 11:

int const x = 42; constexpr int const *px = &x; // both the value of "px" and the value of "*px" are prvalue constant expressions int array[*px]; int main() { return sizeof(array); }

Si es así, ¿por qué un puntero no puede ser una expresión constante? Si no, ¿por qué los programas anteriores no se compilan?

Esta es una limitación conocida en la redacción de la Norma: actualmente solo permite otros parámetros de plantilla como argumentos y & object , para un parámetro de plantilla de tipo de puntero. Aunque el compilador debería ser capaz de hacer mucho más.


Todavía no está permitido en C ++ 0x. temp.arg.nontype requiere:

Un argumento de plantilla para un parámetro de plantilla que no sea de tipo y sin plantilla será uno de:

  • para un parámetro de plantilla sin tipo de tipo integral o de enumeración, una expresión de constante convertida (5.19) del tipo del parámetro de plantilla; o
  • el nombre de un parámetro de plantilla sin tipo; o
  • una expresión constante (5.19) que designa la dirección de un objeto con una duración de almacenamiento estática y un enlace externo o interno o una función con enlace externo o interno, incluyendo plantillas de función e id. de plantilla de función pero excluyendo miembros de clase no estáticos, expresados ​​(ignorando paréntesis) como & id-expression , excepto que & puede omitirse si el nombre se refiere a una función o matriz y debe omitirse si el parámetro-plantilla correspondiente es una referencia; o
  • una expresión constante que se evalúa como un valor de puntero nulo (4.10); o
  • una expresión constante que evalúa a un valor de puntero de miembro nulo (4.11); o
  • un puntero al miembro expresado como se describe en 5.3.1.

respuesta original:

  1. En C ++ 03, solo las expresiones integrales pueden ser expresiones constantes.
  2. Porque el estándar lo dice (naturalmente).
  3. En C ++ 0x, n3290 incluye ejemplos que usan constexpr en un puntero. Entonces, lo que está intentando ahora debería ser posible, aunque ahora debe usar la palabra clave constexpr lugar de const nivel superior.

También hay un error de gcc involucrado, g ++ rechaza los ejemplos propios del borrador estándar de uso de constexpr .