¿Por qué C++11 constexpr es tan restrictivo?


Como probablemente sabrás, C++11 introduce la palabra clave constexpr.

C++11 introdujo la palabra clave constexpr, que permite al usuario garantizar que un constructor de función u objeto es un tiempo de compilación constante. [...] Esto permite al compilador comprender, y verificar, que [function name] es un constante de tiempo de compilación.

Mi pregunta es por qué hay restricciones tan estrictas en la forma de las funciones que se pueden declarar. Entiendo el deseo de garantizar esa función es pura, pero considera esto:

El uso de constexpr en una función impone algunas limitaciones a lo que esa función puede hacer. Primero, la función debe tener un retorno no nulo tipo. En segundo lugar, el cuerpo de la función no puede declarar variables o definir nuevo tipo. Tercero, el cuerpo solo puede contener declaraciones, declaraciones nulas y una sola declaración de retorno. Debe existir valores de argumento tales que, después de la sustitución del argumento, la expresión en el retorno instrucción produce una expresión constante.

Eso significa que esta función pura es ilegal:

constexpr int maybeInCppC1Y(int a, int b)
{
    if (a>0)
        return a+b;
    else
        return a-b;
  //can be written as   return  (a>0) ? (a+b):(a-b); but that isnt the point
}

Tampoco se pueden definir variables locales... :( Así que me pregunto ¿es esto una decisión de diseño, o los compiladores apestan cuando se trata de probar que la función a es pura?

Author: Lightness Races in Orbit, 2011-11-29

5 answers

La razón por la que necesitaría escribir sentencias en lugar de expresiones es que desea aprovechar las capacidades adicionales de las sentencias, particularmente la capacidad de bucle. Pero para ser útil, eso requeriría la capacidad de declarar variables (también prohibidas).

Si combina una facilidad para bucles, con variables mutables, con ramificación lógica (como en las sentencias if), entonces tiene la capacidad de crear bucles infinitos. No es posible determinar si un bucle siempre termina ( el problema de detención ). Por lo tanto, algunas fuentes causarían que el compilador se colgara.

Mediante el uso de funciones puras recursivas es posible causar recursión infinita, que se puede demostrar que es equivalentemente potente a las capacidades de bucle descritas anteriormente. Sin embargo, C++ ya tiene ese problema en tiempo de compilación - ocurre con la expansión de plantillas - y por lo que los compiladores ya tienen que tener un interruptor para "profundidad de pila de plantillas" para que sepan cuándo darse por vencido.

Así que el las restricciones parecen diseñadas para asegurar que este problema (de determinar si una compilación de C++ terminará alguna vez) no se vuelva más espinoso de lo que ya es.

 28
Author: Daniel Earwicker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-29 10:20:45

Las reglas para las funciones constexpr están diseñadas de tal manera que es imposible escribir una función constexpr que tenga efectos secundarios.

Al requerir que constexpr no tenga efectos secundarios, se vuelve imposible para un usuario determinar dónde/cuándo se evaluó realmente. Esto es importante ya que constexpr se permite que las funciones sucedan tanto en tiempo de compilación como en tiempo de ejecución a discreción del compilador.

Si se permitieran los efectos secundarios, entonces tendría que haber algunas reglas sobre el orden en que se observarían. Eso sería increíblemente difícil de definir, incluso más difícil que el problema del orden de inicialización static.

Un conjunto relativamente simple de reglas para garantizar que estas funciones estén libres de efectos secundarios es requerir que sean solo una sola expresión (con algunas restricciones adicionales además de eso). Esto suena limitante inicialmente y descarta la declaración if como usted señaló. Si bien ese caso en particular no tendría efectos secundarios, sí tendría introdujo complejidad adicional en las reglas y dado que se pueden escribir las mismas cosas usando el operador ternario o recursivamente, no es realmente un gran problema.

N2235 es el documento que propuso la adición constexpr en C++. Discute lo racional para el diseño-la cita relevante parece ser ésta de una discusión sobre destructores, pero relevante en general:

La razón es que una expresión constante está destinada a ser evaluada por el compilador en tiempo de traducción al igual que cualquier otro literal de tipo incorporado; en particular no se permiten efectos secundarios observables.

Curiosamente, el documento también menciona que una propuesta anterior sugirió que el compilador averiguó automáticamente qué funciones eran constexpr sin la nueva palabra clave, pero esto se encontró que era inviablemente complejo, lo que parece apoyar mi sugerencia de que las reglas fueron diseñadas para ser simples.

(Sospecho que habrá otras citas en las referencias citado en el documento, pero esto cubre el punto clave de mi argumento sobre la ausencia de efectos secundarios)

 28
Author: Flexo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-29 18:22:46

En realidad, el comité de estandarización de C++ está pensando en eliminar varias de estas restricciones para c++14. Véase el siguiente documento de trabajo http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3597.html

 12
Author: hivert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-18 16:44:18

Las restricciones ciertamente se podrían levantar un poco sin habilitar el código que no se puede ejecutar durante el tiempo de compilación, o que no se puede demostrar que siempre se detenga. Sin embargo, supongo que no se hizo porque

  • Complicaría el compilador para obtener una ganancia mínima. Los compiladores de C++ son bastante complejos como es

  • Especificar exactamente cuánto se permite sin violar las restricciones anteriores habría llevado mucho tiempo, y dado que las características deseadas han sido pospuesto para sacar el estándar de la puerta, probablemente había poco incentivo para agregar más trabajo (y más retraso del estándar) para poca ganancia

  • Algunas de las restricciones habrían sido bastante arbitrarias o bastante complicadas (especialmente en bucles, dado que C++ no tiene el concepto de un bucle for de incremento nativo, pero tanto la condición final como el código de incremento tienen que especificarse explícitamente en la instrucción for, lo que permite usar expresiones arbitrarias para ellos)

Por supuesto, solo un miembro del comité de normas podría dar una respuesta autorizada si mis suposiciones son correctas.

 3
Author: celtschk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-29 19:24:52

Creo que constexpr es solo para objetos const. Quiero decir; ahora puede tener objetos estáticos const como String::empty_string construye estáticamente (sin hacking!). Esto puede reducir el tiempo antes de llamar a 'main'. Y los objetos estáticos const pueden tener funciones como .length(), operator==,..., por lo que es necesario 'expr'. En ' C ' puede crear estructuras constantes estáticas como las siguientes:

static const Foos foo = { .a = 1, .b = 2, };

El kernel de Linux tiene toneladas de clases de este tipo. En c++ puedes hacer esto ahora con constexpr.

Nota: No sé pero el código de abajo no debería ser aceptado así como si la versión:

constexpr int maybeInCppC1Y(int a, int b) { return (a > 0) ? (a + b) : (a - b); }
 -4
Author: Abdurrahim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-01 11:08:31