es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Usando gráficos de punteros en funciones constexpr

Estoy tratando de entender las reglas de constexpr en relación a los punteros, contenidos dentro de estructuras de datos constexpr, que hacen referencia a otras partes de esa estructura de datos constexpr.

Considere el siguiente fragmento de código:

struct selfref{
    selfref *next{nullptr};
};

struct exec{
    selfref mem[1] = {selfref{}};
    constexpr exec(){
    mem[0].next = &mem[0];
    }
};

Si intento instanciar exec como una variable local constexpr, puedo seguir los punteros desde ella:

int main(){
    static constexpr exec ret;
    static constexpr selfref *ptr = ret.mem[0].next;
}

Pero si en cambio la retorno desde una función trivial y no cambio nada más:

constexpr exec do_thing(){
    return exec{};
}

int main(){
    static constexpr auto ret = do_thing();
    static constexpr selfref *ptr = ret.mem[0].next;
}

De repente obtengo un error con g++-11 y g++-12:

minimal-interesting-example2.cpp: In function ‘int main()’:
minimal-interesting-example2.cpp:18:42: error: ‘exec{selfref [1]{selfref{(<anonymous>.exec::mem[0])}}}’ is not a constant expression
   18 |     static constexpr auto ret = do_thing();
      |

Pero no con clang++-13. Demo: link

¿Cuál compilador tiene razón? Y sin importar esa respuesta, ¿qué está sucediendo aquí?

EDIT: Parece que GCC al menos cree que este código debería funcionar según este reporte de error: link. Aun así, me interesaría mucho saber si hay alguien que conozca el estándar y pueda confirmar que esto debería funcionar.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    La pregunta gira en torno al comportamiento del especificador constexpr y su interacción con punteros contenidos dentro de estructuras de datos constexpr que hacen referencia a otras partes de esa misma estructura de datos. El fragmento específico de código incluye una estructura selfref que contiene un miembro next, el cual es un puntero a una estructura selfref. Otra estructura exec contiene un arreglo mem de estructuras selfref y define un constructor constexpr que inicializa mem[0].next para que apunte al primer elemento de mem. El comportamiento de este código se prueba instanciando exec como una constante constexpr local en main y siguiendo los punteros desde ella, y posteriormente devolviéndola desde una función trivial y siguiendo los punteros desde ella.

    El problema con el segundo caso de prueba es que, aunque se compila correctamente con clang++-13, produce un error con g++-11 y g++-12. El mensaje de error indica que exec { selfref [1] { selfref { (&<anonymous>.exec::mem[0]) }}} no es una expresión constante. Esto significa que g++-11 y g++-12 no pueden evaluar la llamada constexpr a do_thing() en tiempo de compilación, a pesar de que devuelve un objeto constexpr. Este comportamiento contradice lo que sugiere el informe de error de GCC mencionado en la edición.

    Es difícil decir definitivamente cuál compilador es correcto sin referirse al estándar C++20. Sin embargo, el hecho de que el código se comporte de manera diferente entre los dos compiladores sugiere que puede haber cierta ambigüedad o falta de claridad en el estándar con respecto a este escenario específico. Es posible que clang++-13 esté implementando una interpretación más permisiva del estándar mientras que g++-11 y g++-12 se adhieren más estrictamente a él.

    En general, el especificador constexpr indica al compilador que una expresión puede ser evaluada en tiempo de compilación y, por lo tanto, se puede utilizar en contextos que requieren expresiones constantes. Sin embargo, el comportamiento de constexpr en escenarios más complejos que involucran punteros y estructuras de datos puede ser difícil de entender. En este caso, parece que el uso de punteros dentro de estructuras de datos constexpr está causando dificultades a los compiladores para evaluar las expresiones involucradas.

Comments are closed.