¿Por qué lo siguiente me da un error de conversión de doble *** a doble const? ***

¿Por qué no puede convertir el double *** const double *** ?

 void foo(const double ***d) { } int main (int args, char*[] args) { double ***d; /*initialize d */ foo(d); } 

Si se cree su etiqueta C, gcc genera una advertencia ya que los tipos difieren tanto para su ejemplo como para const double * const * const * d . En C ++, es un error en el código OP, pero el enfoque slap-const-everywhere es legal.

La razón por la que el comstackdor le advierte es que un puntero a un puntero (o una dirección indirecta adicional) permite que se devuelva un puntero a la persona que llama al modificar la ubicación a la que apunta el parámetro.

Si el objective del puntero se declara como constante, la función llamada esperaría que el valor que pone allí sea tratado como constante en el retorno.

Un caso más simple de pasar una T** a una const T** que ilustra por qué esto es un error sería:

 void foo ( const char ** z ) { *z = "A"; } int main (int nargs, char** argv) { char* z = 0; char** d = &z; // warning in C, error in C++ foo ( d ); // bad - modifies const data z[0] = 'Q'; } 

const en C significa que los datos no cambiarán. const en C ++ significa que los datos no cambiarán públicamente; los datos mutables en un objeto C ++ pueden cambiar. El comstackdor de CA puede optimizar su código para que almacene en caché algunos de los datos const algún lugar, pero un comstackdor de C ++ no puede hacer eso debido a la posibilidad de mudanza, por lo que tiene la restricción más débil de que no puede devolver los datos const a los no constantes como se indica anteriormente . Por lo tanto, en C ++, el double*** se puede convertir en const double * const * const * d ya que las const adicionales impiden el retorno de la memoria no modificable, pero en C genera una advertencia y posibles errores si el comstackdor optimiza los accesos repetidos a la memoria en otro lado.

La respuesta a su pregunta se puede encontrar en http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17

Esto significa que realmente debería usar const double * const * const * d .

usar const_cast_operator ()

Esto también es válido para ** (un puntero a puntero) por razones idénticas.

Este código también produce este error, y es más claro ver por qué el comstackdor no te deja hacer esto aquí:

  double d = 0.0; double * pd = &d; const double ** ppd = &pd; // <--- Error 

Si pudiera hacer esto, podría tener un puntero 'const' a los datos (ppd), que podría cambiar al cambiar el valor mutable d. Esto viola a const, por lo que el comstackdor no te permitirá hacer esto.

Considere d un puntero a una caja negra.

El comstackdor puede agregar const a d propio o al blackbox, pero no a los contenidos del blackbox. Asi que

 void foo1(double ***d); /* ok, no casts needed */ void foo2(double *** const d); /* ok, no casts needed; const added to `d` itself */ void foo3(double ** const *d); /* ok, no casts needed; const added to the blackbox */ void foo4(double * const **d); /* oops, trying to change the insides of the blackbox */ void foo5(const double ***d); /* oops, trying to change the insides of the blackbox */ void foo6(double ** const * const d); /* ok: d is a constant pointer to a constant blackbox */ 

Con const double *** d solo el valor de d es const . En C, la conversión del doble a al const doble * a es legal, mientras que la conversión del doble b al const doble ** b (u otra dirección indirecta) no lo es.

Por lo tanto, para convertir de doble *** d a const doble *** d2 , puede hacer lo siguiente:

   doble *** d;
   const doble * b = ** d;
   const doble ** c = & b;
   const doble *** d2 = & c;

Por supuesto, el uso de const double *** d sigue siendo cuestionable debido a las direcciones no constantes.