24 votos

¿Por qué no puede un puntero constante a ser una expresión constante?

El siguiente programa se compila:

template <const int * P>
class Test{};

extern const int var = 42; //extern needed to force external linkage

int main()
{
    Test<&var> test;
}

Éste, sin embargo, que no, que 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.
}

Alternativa de ejemplo:

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 no puede ser una expresión constante, independientemente de si se es constante y se inicializa con una expresión constante.

Preguntas:

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

Gracias por los puntos de vista!

9voto

Johannes Schaub - litb Puntos 256113

Es un poco más complicado. En C++03 y C++11, &var es una expresión de la constante de si var es un local estático / estático de clase o espacio de alcance variable. Esto se llama una dirección constante de la expresión. Inicializar una clase estática o espacio de alcance variable de puntero con la expresión de la constante está garantizada para ser hecho antes de que cualquier código que se ejecuta (estática fase de inicialización), por tratarse de una expresión constante.

Sin embargo, sólo en C++11, un constexpr puntero variable que almacena la dirección &var también puede ser utilizado como una dirección constante de la expresión y sólo en C++11, puede eliminar una dirección constante de la expresión (en realidad, usted puede eliminar incluso más - incluso el local, el elemento de matriz de direcciones, pero vamos a mantenerlo ontopic) y si se refiere a una constante integral variable inicializada antes de la eliminación de referencias o un constexpr variable, de nuevo obtener una expresión de la constante (dependiendo del tipo y valor de la categoría, el tipo de expresión de la constante puede variar). Como tal, el siguiente es válido en 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é no puede un puntero ser una expresión constante? Si no, ¿por qué no los anteriores programas de compilación?

Esta es una limitación conocida en el Estándar de la redacción, actualmente sólo permite que otros parámetros de la plantilla como argumentos o & object, para un parámetro de plantilla de tipo de puntero. Aunque el compilador debe ser capaz de hacer mucho más.

2voto

Ben Voigt Puntos 151460

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

Una plantilla con el argumento de que un no-tipo, sin plantilla plantilla parámetro será uno de:

  • para un no-tipo de plantilla-parámetro de integral o tipo de enumeración, una antigua expresión de la constante de (5.19) del tipo de la plantilla-parámetro; o
  • el nombre de un no-tipo de plantilla-parámetro; o
  • una expresión de la constante de (5.19) que designa a la dirección de un objeto estático tiempo de almacenamiento y externa o interna de la vinculación o una función externa o interna de la vinculación, como la función de las plantillas y la función de la plantilla de id, pero excluyendo a los no-estática de los miembros de la clase, expresa (ignorando paréntesis) como & id-expression, salvo que el y puede ser omitido si el nombre se refiere a una función o matriz y se ser omitido si la plantilla correspondiente parámetro es una referencia; o
  • una constante de la expresión que se evalúa como un valor de puntero nulo (4.10); o
  • una constante de la expresión que se evalúa como un miembro null valor de puntero (4.11); o
  • un puntero a miembro expresa como se describe en 5.3.1.

original respuesta:

  1. En C++03, sólo integral expresiones pueden ser expresiones constantes.
  2. Debido a que la norma dice así (de forma natural).
  3. En C++0x, n3290 incluye ejemplos de uso constexpr en un puntero. Así que lo que están tratando de ahora debería ser posible, aunque ahora debe utilizar el constexpr de palabras clave en lugar de la de nivel superior, const.

También hay una gcc error involucrados, g++ rechaza el borrador de estándar propio de ejemplos válidos constexpr de uso.

1voto

Mooing Duck Puntos 27497

El problema es debido a su programa de C++ pueden ser cargados en cualquier punto en la memoria, y por lo que la dirección de global var puede ser diferente cada vez que se ejecute el programa. ¿Qué sucede si usted ejecuta el programa dos veces? var es, obviamente, en dos lugares diferentes, a continuación,.

Peor aún, en tu ejemplo, tomar la dirección de una variable en la pila! mira esto:

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

Si main llama myfunction(3), luego 3 myvars se crean en lugares separados. No hay manera de que el tiempo de compilación para saber cómo muchos myvars se crean, mucho menos hay ubicaciones exactas.

Por último: la declaración de una variable a ser const significa: "yo prometo", y qué no decir que es una compilación de constante de tiempo. Vea 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.
}

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X