puntero typedef con rareza

por favor considere el siguiente código:

typedef struct Person* PersonRef; struct Person { int age; }; const PersonRef person = NULL; void changePerson(PersonRef newPerson) { person = newPerson; } 

Por algún motivo, el comstackdor se queja de que el valor de solo lectura no es asignable. Pero la palabra clave const no debe hacer que el puntero sea const. ¿Algunas ideas?

Tenga en cuenta que

 typedef int* intptr; const intptr x; 

no es lo mismo que:

 const int* x; 

intptr es un puntero a int. const intptr es puntero constante a int , no puntero a constante int .

Entonces, después de un puntero typedef, ¿ya no puedo hacer que esté relacionado con el contenido?

Hay algunas formas desagradables, como typefo macro de gcc:

 typedef int* intptr; intptr dummy; const typeof(*dummy) *x; 

pero, como ve, no tiene sentido si conoce el tipo detrás de intptr .

 const PersonRef person = NULL; 

es

 struct Person*const person= NULL; 

entonces estás construyendo el puntero y no el objeto.

Si bien el problema ya está resuelto por las respuestas anteriores, echo de menos la razón por la cual …

Así que tal vez como regla general:

  1. El const siempre se refiere a su token predecesor.
  2. En caso de que no exista tal cosa, se trata de “consting”, es su token sucesor.

Esta regla realmente puede ayudar a declarar un puntero a punteros const o algo igualmente limpio.

De todos modos, con esto en mente, debería quedar claro por qué

 struct Person *const person = NULL; 

declara un puntero const a una estructura mutable.

Piénselo, su typedef “agrupa” la struct Person con el token del puntero * . Entonces, para escribir

 const PersonRef person = NULL; 

su comstackdor ve algo así (pseudo-código):

 const [struct Person *]person = NULL; 

Como no queda nada a la izquierda, deklares el token a su derecha struct Person * constante.

Bueno, creo, esta es la razón por la que no me gusta ocultar punteros por typedefs, mientras que me gustan los typedefs como tal. ¿Qué hay de escribir

 typedef struct Person { ... } Person; const Person *person; /*< const person */ Person *const pointer; /*< const pointer to mutable person */ 

y debería ser bastante claro para los comstackdores y los humanos, lo que estás haciendo.

Nunca oculte los punteros detrás de typedefs, es realmente una mala práctica y solo creará errores.

Un error tan infame es que un tipo de puntero typedef: ed que se declara como const se tratará como un “puntero constante a datos no constantes”, en lugar de “un puntero no constante a datos constantes” que es lo que se espera intuitivamente . Esto es lo que sucede en tu progtwig.


Solución:

 typedef struct { int age; } Person; const Person* person = NULL; // non-constant pointer to constant Person 

estás recibiendo y error

 error: assignment of read-only variable 'person' 

en la statement

 person = newPerson; 

porque has declarado a la persona como const, por lo que su valor es solo de lectura … el valor const no se puede cambiar

si vas a cambiar eso vatiable entonces ¿por qué lo estás pidiendo const?

eliminar la palabra clave const tu código funcionará bien

Como una adición a la respuesta de Piotr (aceptada), es posible evitar typeof específicos de GCC:

 static_assert(std::is_same> *>::value, "not same via type_traits"); static_assert(std::is_same*>::value, "not same via decltype"); 

Cambiando foo_t a foo::type arriba y / o usando la versión de boost, incluso es posible hacer esto en C ++ 98, aunque solo es bastante desde C ++ 11.


Alternativamente, use dos typedefs diferentes, que también funciona para casos que no sean punteros simples. Por ejemplo, considere el iterator cada contenedor y el const_iterator .