Namespaces
Variants

Constant expressions

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Define una expresión que puede ser evaluada en tiempo de compilación.

Tales expresiones pueden utilizarse como argumentos de plantilla constantes, tamaños de array, y en otros contextos que requieran expresiones constantes, p. ej.

int n = 1;
std::array<int, n> a1;  // Error: “n” no es una expresión constante
const int cn = 2;
std::array<int, cn> a2; // OK: “cn” es una expresión constante

Contenidos

Definición

Una expresión que pertenezca a cualquiera de las categorías de expresión constante enumeradas a continuación es una expresión constante .

Categorías de expresión constante de C++98

Expresión constante integral (C++98)

En los siguientes contextos, C++ requiere expresiones que evalúen a una constante integral o de enumeración:

Una expresión que cumpla todas las siguientes condiciones es una expresión constante integral :

  • Solo involucra las siguientes entidades:
  • literales de tipos aritméticos
  • enumeradores
  • variables o miembros de datos estáticos que cumplan todas las siguientes condiciones:
  • Están calificados como const.
  • No están calificados como volatile.
  • Son de tipos integrales o de enumeración.
  • Están inicializados con expresiones constantes.
  • No utiliza literales de punto flotante, a menos que sean convertidos explícitamente a tipos integrales o de enumeración.
  • No aplica ninguna conversión a tipos no integrales y no de enumeración.
  • No utiliza ninguna de las siguientes entidades excepto en los operandos de sizeof :
  • función
  • objeto de clase
  • puntero
  • referencia
  • operador de asignación
  • operador de incremento
  • operador de decremento
  • operador de llamada a función
  • operador coma

Otras categorías de expresión constante

Otras expresiones se consideran expresiones constantes solo para el propósito de inicialización constante . Dicha expresión constante debe ser una de las siguientes expresiones:

  • una expresión que evalúa a un valor de puntero nulo
  • una expresión que evalúa a un valor de puntero-a-miembro nulo
  • una expresión constante aritmética
  • una expresión constante de dirección
  • una expresión constante de referencia
  • una expresión constante de dirección para un tipo de objeto completo, más o menos una expresión constante integral
  • una expresión constante de puntero-a-miembro

Una expresión constante aritmética es una expresión que cumple los requisitos para una expresión constante integral, con las siguientes excepciones:

  • Se pueden usar literales de punto flotante sin conversión explícita.
  • Se pueden aplicar conversiones a tipos de punto flotante.

Una expresión constante de dirección es una expresión de tipo puntero que cumple todas las siguientes condiciones:

  • usando explícitamente el operador dirección-de
  • usando implícitamente un parámetro de plantilla constante de tipo puntero
  • usando una expresión de tipo arreglo o función
  • La expresión no llama a ninguna función.
  • La expresión usa conversiones explícitas de puntero (excepto dynamic_cast ) y los siguientes operadores sin acceder al objeto resultado:
  • operador subíndice
  • operador de indirección
  • operador dirección-de
  • operador de acceso a miembro
  • Si se usa el operador subíndice, uno de sus operandos es una expresión constante integral.

Una expresión constante de referencia es una expresión de tipo referencia que cumple todas las siguientes condiciones:

  • La referencia designa un objeto con duración de almacenamiento estático, un parámetro de plantilla constante de tipo referencia, o una función. La referencia no designa un miembro o clase base de tipo de clase no POD.
  • La expresión no llama a ninguna función.
  • La expresión usa conversiones explícitas de referencia (excepto dynamic_cast ) y los siguientes operadores sin acceder al objeto resultado:
  • operador subíndice
  • operador de indirección
  • operador dirección-de
  • operador de acceso a miembro
  • Si se usa el operador subíndice, uno de sus operandos es una expresión constante integral.

Una expresión constante de puntero-a-miembro es una expresión de tipo puntero-a-miembro donde el puntero se crea aplicando el operador dirección-de a un identificador calificado, opcionalmente precedido por una conversión explícita de puntero-a-miembro.

(hasta C++11)

Las siguientes expresiones se denominan colectivamente expresiones constantes :

  • la dirección de un objeto con static storage duration
  • la dirección de una función
  • un null pointer value
(desde C++11)
(hasta C++14)

Las siguientes entidades son resultados permitidos de una expresión constante :

Una expresión constante es un glvalue expresión constante central que se refiere a una entidad que es un resultado permitido de una expresión constante, o una prvalue expresión constante central cuyo valor satisface las siguientes restricciones:

  • Si el valor es un objeto de tipo clase, cada miembro de datos no estático de tipo referencia se refiere a una entidad que es un resultado permitido de una expresión constante.
  • Si el valor es un objeto de tipo escalar , no tiene un valor indeterminado .
  • Si el valor es de tipo puntero , es uno de los siguientes valores:
  • la dirección de un objeto con duración de almacenamiento estático
  • la dirección pasando el final de un objeto con duración de almacenamiento estático
  • la dirección de una función no inmediata (desde C++20)
  • un valor de puntero nulo
  • Si el valor es de tipo puntero-a-función-miembro, no designa una función inmediata.
(desde C++20)
  • Si el valor es un objeto de tipo clase o tipo array, cada subobjeto satisface estas restricciones para el valor.
(desde C++14)
(hasta C++26)

Una expresión constante es un glvalue expresión constante del núcleo que se refiere a un objeto o una función no inmediata , o un prvalue expresión constante del núcleo cuyo valor satisface las siguientes restricciones:

(desde C++26)

Al determinar si una expresión es una expresión constante, copy elision se asume que no se realiza.

La definición de C++98 de expresiones constantes está completamente dentro del cuadro colapsable. La siguiente descripción se aplica a C++11 y versiones posteriores de C++.

Tipo literal

Los siguientes tipos se denominan colectivamente literal types :

  • Tiene un trivial destructor (until C++20) constexpr destructor (since C++20) .
  • Todos sus miembros de datos no estáticos no variantes y clases base son de tipos literales no volátiles.
  • Es uno de los siguientes tipos:
(desde C++17)
  • un tipo de unión agregado que satisface una de las siguientes condiciones:
  • No tiene ningún miembro variante .
  • Tiene al menos un miembro variante de tipo literal no volátil.
  • No tiene ningún miembro variante.
  • Tiene al menos un miembro variante de tipo literal no volátil.
  • un tipo con al menos un constructor (plantilla) constexpr que no sea un constructor de copia o movimiento

Solo los objetos de tipos literales pueden crearse dentro de una expresión constante.

Expresión constante principal

Una expresión constante principal es cualquier expresión cuya evaluación no evaluaría ninguna de las siguientes construcciones del lenguaje:

Constructo del lenguaje Versión Documento(s)
el puntero this , excepto en una constexpr function que está siendo evaluada como parte de la expresión, o cuando aparece en una expresión de acceso a miembro de clase implícita o explícita N2235
un flujo de control que pasa a través de una declaración de una variable de bloque con duración de almacenamiento estática o de hilo storage duration que no es usable in constant expressions (since C++23) P2242R3
  1. a function call expression that calls a function (or a constructor) that is not declared constexpr
    constexpr int n = std::numeric_limits<int>::max(); // OK: max() es constexpr
    constexpr int m = std::time(nullptr); // Error: std::time() no es constexpr
  2. a function call to a constexpr function which is declared, but not defined
  3. a function call to a constexpr function/constructor template instantiation where the instantiation fails to satisfy función/constructor constexpr requirements.
  4. a function call to a constexpr virtual function, invoked on an object whose dynamic type is constexpr-unknown
  5. an expression that would exceed the implementation-defined limits
  6. an expression whose evaluation leads to any form of core language undefined o erróneo (since C++26) behavior, except for any potential undefined behavior introduced by atributos estándar .
    constexpr double d1 = 2.0 / 1.0; // OK
    constexpr double d2 = 2.0 / 0.0; // Error: no definido
    constexpr int n = std::numeric_limits<int>::max() + 1; // Error: desbordamiento
    int x, y, z[30];
    constexpr auto e1 = &y - &x;        // Error: indefinido
    constexpr auto e2 = &z[20] - &z[3]; // OK
    constexpr std::bitset<2> a; 
    constexpr bool b = a[2]; // Comportamiento indefinido, pero no especificado si se detecta
  7. (hasta C++17) a expresión lambda
  8. an lvalue-to-rvalue conversión implícita unless applied to...
    1. un glvalue de tipo (posiblemente calificado con cv) std::nullptr_t
    2. un glvalue de tipo-literal no volátil que designa un objeto que es utilizable en expresiones constantes
      int main()
      {
          const std::size_t tabsize = 50;
          int tab[tabsize]; // OK: tabsize es una expresión constante
                            // porque tabsize es utilizable en expresiones constantes
                            // porque tiene tipo integral calificado con const, y
                            // su inicializador es un inicializador constante
          std::size_t n = 50;
          const std::size_t sz = n;
          int tab2[sz]; // Error: sz no es una expresión constante
                        // porque sz no es utilizable en expresiones constantes
                        // porque su inicializador no fue un inicializador constante
      }
    3. un glvalue de tipo-literal no volátil que se refiere a un objeto no volátil cuyo tiempo de vida comenzó dentro de la evaluación de esta expresión
  9. an lvalue-to-rvalue conversión implícita or modification applied to a non-active member of a union or its subobject (even if it shares a common initial sequence with the active member)
  10. an lvalue-to-rvalue implicit conversion on an object cuyo valor es indeterminado
  11. an invocation of implicit copy/move constructor/assignment for a union whose active member is mutable (if any), with lifetime beginning outside the evaluation of this expression
  12. (hasta C++20) an assignment expression that would change the active member of a union
  13. conversion from puntero a void to a pointer-to-object type T* a menos que el puntero contenga un valor de puntero nulo o apunte a un objeto cuyo tipo sea similar a T (since C++26)
  14. dynamic_cast cuyo operando es un glvalue que se refiere a un objeto cuyo tipo dinámico es constexpr-desconocido (desde C++20)
  15. reinterpret_cast
  16. (hasta C++20) pseudo-destructor call
  17. (hasta C++14) an increment or a decrement operator
  18. (desde C++14) modification of an object, unless the object has non-volatile literal type and its lifetime began within the evaluation of the expression
    constexpr int incr(int& n)
    {
        return ++n;
    }
    constexpr int g(int k)
    {
        constexpr int x = incr(k); // Error: incr(k) no es una expresión constante central
                                   // porque el tiempo de vida de k
                                   // comenzó fuera de la expresión incr(k)
        return x;
    }
    constexpr int h(int k)
    {
        int x = incr(k); // OK: x no necesita ser inicializado
                         // con una expresión constante central
        return x;
    }
    constexpr int y = h(1); // OK: inicializa y con el valor 2
                            // h(1) es una expresión constante central porque
                            // el tiempo de vida de k comienza dentro de la expresión h(1)
  19. (desde C++20) a destructor call or pseudo destructor call for an object whose lifetime did not begin within the evaluation of this expression
  20. a typeid expression applied to a glvalue of polymorphic type y ese glvalue se refiere a un objeto cuyo tipo dinámico es constexpr-desconocido (desde C++20)
  21. a new expresión , a menos que se cumpla una de las siguientes condiciones: (desde C++20)
    • La función de asignación seleccionada es una función de asignación global reemplazable y el almacenamiento asignado se desasigna dentro de la evaluación de esta expresión.
    (since C++20)
    • La función de asignación seleccionada es una forma no asignadora con un tipo asignado T , y el argumento de colocación satisface todas las siguientes condiciones:
    • Apunta a:
    • un objeto cuyo tipo es similar a T , si T no es un tipo array, o
    • el primer elemento de un objeto de un tipo similar a T , si T es un tipo array.
    • Apunta a almacenamiento cuya duración comenzó dentro de la evaluación de esta expresión.
    (since C++26)
  22. a delete expresión , a menos que desasigne una región de memoria asignada dentro de la evaluación de esta expresión (since C++20)
  23. (desde C++20) Coroutines: an expresión await or a expresión-yield
  24. (desde C++20) a comparación de tres vías when the result is unspecified
  25. an equality or relational operator whose result is unspecified
  26. (hasta C++14) an assignment or a compound assignment operator
  27. (hasta C++26) una expresión throw
  28. (desde C++26) una construcción de un objeto de excepción, a menos que el objeto de excepción y todas sus copias implícitas creadas por invocaciones de std::current_exception o std::rethrow_exception sean destruidas dentro de la evaluación de esta expresión
    constexpr void check(int i)
    {
        if (i < 0)
            throw i;
    }
    constexpr bool is_ok(int i)
    {
        try {
            check(i);
        } catch (...) {
            return false;
        }
        return true;
    }
    constexpr bool always_throw()
    {
        throw 12;
        return true;
    }
    static_assert(is_ok(5)); // OK
    static_assert(!is_ok(-1)); // OK desde C++26
    static_assert(always_throw()); // Error: excepción no capturada
  29. una declaración asm
  30. una invocación de la macro va_arg
  31. una sentencia goto
  32. una expresión dynamic_cast o typeid o una expresión new (desde C++26) que lanzaría una excepción donde no hay disponible una definición del tipo de excepción (desde C++26)
  33. dentro de una expresión lambda, una referencia a this o a una variable definida fuera de esa lambda, si esa referencia sería un odr-use
    void g()
    {
        const int n = 0;
        constexpr int j = *&n; // OK: fuera de una expresión lambda
        [=]
        {
            constexpr int i = n;   // OK: 'n' no es odr-used y no se captura aquí.
            constexpr int j = *&n; // Mal formado: '&n' sería un odr-use de 'n'.
        };
    }

    nótese que si el odr-use ocurre en una llamada a función de un cierre, no se refiere a this o a una variable envolvente, ya que accede a un miembro de datos del cierre en su lugar

    // OK: 'v' & 'm' son odr-used pero no ocurren en una expresión constante
    // dentro de la lambda anidada
    auto monad = [](auto v){ return [=]{ return v; }; };
    auto bind = [](auto m){ return [=](auto fvm){ return fvm(m()); }; };
    // OK tener capturas de objetos automáticos creados durante la evaluación de expresión constante.
    static_assert(bind(monad(2))(monad)() == monad(2)());
    (desde C++17)

Requisitos adicionales

Aunque una expresión E no evalúe nada mencionado anteriormente, está definido por la implementación si E es una expresión constante del núcleo si evaluar E resultaría en comportamiento indefinido en tiempo de ejecución .

Aunque una expresión E no evalúe nada de lo mencionado anteriormente, no está especificado si E es una core constant expression si evaluar E evaluaría cualquiera de los siguientes:

Para los propósitos de determinar si una expresión es una expresión constante núcleo, la evaluación del cuerpo de una función miembro de std:: allocator < T > se ignora si T es un tipo literal.

Para los propósitos de determinar si una expresión es una expresión constante central, la evaluación de una llamada a un constructor de copia/desplazamiento trivial u operador de asignación de copia/desplazamiento de una union se considera que copia/desplaza el miembro activo de la union, si existe alguno.

Para determinar si una expresión es una expresión constante del núcleo, la evaluación de una expresión de identificador que nombra un structured binding bd tiene la siguiente semántica:

  • Si bd es un lvalue que se refiere al objeto vinculado a una referencia inventada ref , el comportamiento es como si ref fuera nominada.
  • De lo contrario, si bd nombra un elemento de array, el comportamiento es el de evaluar e [ i ] , donde e es el nombre de la variable inicializada desde el inicializador de la declaración de structured binding, y i es el índice del elemento referido por bd .
  • De lo contrario, si bd nombra un miembro de clase, el comportamiento es el de evaluar e. m , donde e es el nombre de la variable inicializada desde el inicializador de la declaración de structured binding, y m es el nombre del miembro referido por bd .
(since C++26)

Durante la evaluación de la expresión como una expresión constante principal, todas las expresiones de identificador y usos de * this que se refieren a un objeto o referencia cuyo tiempo de vida comenzó fuera de la evaluación de la expresión se tratan como referencias a una instancia específica de ese objeto o referencia cuyo tiempo de vida y el de todos los subobjetos (incluyendo todos los miembros de unión) incluye toda la evaluación constante.

  • Para tal objeto que no es usable en expresiones constantes (desde C++20) , el tipo dinámico del objeto es constexpr-unknown .
  • Para tal referencia que no es usable en expresiones constantes (desde C++20) , la referencia se trata como si se vinculara a un objeto no especificado del tipo referenciado cuyo tiempo de vida y el de todos los subobjetos incluye toda la evaluación constante y cuyo tipo dinámico es constexpr-unknown.

Expresión constante entera

Expresión constante entera es una expresión de tipo entero o de enumeración no delimitada convertida implícitamente a un prvalue, donde la expresión convertida es una expresión constante principal.

Si una expresión de tipo clase se utiliza donde se espera una expresión constante integral, la expresión es convertida implícitamente contextualmente a un tipo integral o de enumeración no acotada.

Expresión constante convertida

Una expresión constante convertida de tipo T es una expresión convertida implícitamente al tipo T , donde la expresión convertida es una expresión constante, y la secuencia de conversión implícita contiene únicamente:

(desde C++17)

Y si tiene lugar cualquier enlace de referencia , solo puede ser enlace directo .

Los siguientes contextos requieren una expresión constante convertida:

(desde C++14)
(desde C++26)

Una expresión constante convertida contextualmente de tipo bool es una expresión convertida contextualmente a bool , donde la expresión convertida es una expresión constante y la secuencia de conversión contiene únicamente las conversiones mencionadas anteriormente.

Los siguientes contextos requieren una expresión constante convertida contextualmente de tipo bool :

(hasta C++23)
(desde C++17)
(hasta C++23)
(desde C++20)


Entidades constituyentes

Los valores constituyentes de un objeto obj se definen de la siguiente manera:

  • Si obj tiene tipo escalar, el valor constituyente es el valor de obj .
  • En caso contrario, los valores constituyentes son los valores constituyentes de cualquier subobjeto directo de obj excepto miembros inactivos de union .

Las referencias constituyentes de un objeto obj incluyen las siguientes referencias:

  • cualquier miembro directo de obj que tenga tipo referencia
  • las referencias constituyentes de cualquier subobjeto directo de obj excepto miembros inactivos de union

Los valores constituyentes y referencias constituyentes de una variable var se definen de la siguiente manera:

  • Si var declara un objeto, los valores y referencias constituyentes son los valores y referencias constituyentes de ese objeto.
  • Si var declara una referencia, la referencia constituyente es esa referencia.

Para cualquier referencia constituyente ref de una variable var , si ref está vinculada a un objeto temporal o subobjeto del mismo cuya duración se extiende a la de ref , los valores y referencias constituyentes de ese objeto temporal también son valores y referencias constituyentes de var , recursivamente.

Entidades representables en constexpr

Los objetos con duración de almacenamiento estático son referenciables en constexpr en cualquier punto del programa.

Un objeto obj con duración de almacenamiento automático es referenciable en constexpr desde un punto P si el ámbito más pequeño que contiene la variable var y el ámbito más pequeño que contiene P son el mismo ámbito de parámetro de función que no se asocia con la lista de parámetros de una requires expresión , donde var es la variable correspondiente al objeto completo de obj o la variable a cuya duración se extiende la de obj .

Un objeto o referencia x es representable en constexpr en un punto P si se cumplen todas las siguientes condiciones:

  • Para cada valor constituyente de x que apunta a un objeto obj , obj es referenciable en constexpr desde P .
  • Para cada valor constituyente de x que apunta más allá de un objeto obj , obj es referenciable en constexpr desde P .
  • Para cada referencia constituyente de x que se refiere a un objeto obj , obj es referenciable en constexpr desde P .
(desde C++26)

Entidades con inicialización constante

Una variable u objeto temporal obj está inicializado-constantemente si se cumplen todas las siguientes condiciones:

  • O bien tiene un inicializador, o su tipo es const-default-constructible .
  • La expresión-completa de su inicialización es una expresión constante en el contexto que requiere una expresión constante, excepto que si obj es un objeto, esa expresión-completa también puede invocar constexpr constructores para obj y sus subobjetos incluso si esos objetos son de tipos de clase no literales.
(hasta C++26)

Una variable var es inicializable-constantemente si se cumplen todas las siguientes condiciones:

  • La expresión-completa de su inicialización es una expresión constante en el contexto que requiere una expresión constante, donde todas las aserciones de contrato utilizan la semántica de evaluación "ignorar".
  • Inmediatamente después de la declaración inicializadora de var , el objeto o referencia declarado por var es representable-constexpr.
  • Si el objeto o referencia x declarado por var tiene duración de almacenamiento estático o de hilo, x es representable-constexpr en el punto más cercano cuyo ámbito inmediato es un ámbito de espacio de nombres que sigue a la declaración inicializadora de var .

Una variable inicializable-constantemente está inicializada-constantemente si o bien tiene un inicializador, o su tipo es const-default-constructible .

(desde C++26)

Utilizable en expresiones constantes

Una variable es potencialmente-constante si es una constexpr variable o tiene tipo de referencia o tipo integral o enumeración calificado como const no volátil.

Una variable potencialmente constante inicializada de forma constante var es utilizable en expresiones constantes en un punto P si la declaración inicializadora D de var es alcanzable desde P y se satisface alguna de las siguientes condiciones:

  • var es una variable constexpr .
  • var no está inicializada con un valor TU-local .
  • P está en la misma unidad de traducción que D .

Un objeto o referencia es utilizable en expresiones constantes en un punto P si es una de las siguientes entidades:

  • una variable que es utilizable en expresiones constantes en P
  • un objeto temporal de tipo literal calificado const no volátil cuya duración se extiende a la de una variable que es utilizable en expresiones constantes en P
  • un objeto de parámetro de plantilla
  • un objeto de literal de cadena
  • un subobjeto no mutable de cualquiera de los anteriores
  • un miembro de referencia de cualquiera de los anteriores
(hasta C++26)

Un objeto o referencia es potencialmente utilizable en expresiones constantes en un punto P si es una de las siguientes entidades:

  • una variable que es utilizable en expresiones constantes en P
  • un objeto temporal de tipo literal calificado const no volátil cuya duración se extiende a la de una variable que es utilizable en expresiones constantes en P
  • un objeto de parámetro de plantilla
  • un objeto de literal de cadena
  • un subobjeto no mutable de cualquiera de los anteriores
  • un miembro de referencia de cualquiera de los anteriores

Un objeto o referencia es utilizable en expresiones constantes en un punto P si es un objeto o referencia que es potencialmente utilizable en expresiones constantes en P y es constexpr-representable en P .

(desde C++26)

Expresiones manifiestamente evaluadas en tiempo de compilación

Las siguientes expresiones (incluyendo conversiones al tipo de destino) son manifestamente evaluadas en tiempo de compilación :

Si una evaluación ocurre en un contexto manifiestamente constante puede detectarse mediante std::is_constant_evaluated y if consteval (desde C++23) .

(desde C++20)

Funciones y variables necesarias para evaluación constante

Las siguientes expresiones o conversiones son potencialmente evaluadas como constantes :

Una función es necesaria para evaluación constante si es una función constexpr y nombrada por una expresión que es potencialmente evaluada de forma constante.

Una variable es necesaria para evaluación constante si es una variable constexpr o es de tipo integral calificado const no volátil o de tipo referencia y la expresión de identificador que la denota es potencialmente evaluada de forma constante.

Definición de una función por defecto e instanciación de una function template specialization o variable template specialization (since C++14) se activan si la función o variable (since C++14) es necesaria para evaluación constante.

Subexpresión constante

Una subexpresión constante es una expresión cuya evaluación como subexpresión de una expresión e no impediría que e sea una expresión constante central , donde e no es ninguna de las siguientes expresiones:

(desde C++20)

Notas

Macro de prueba de características Valor Std Característica
__cpp_constexpr_in_decltype 201711L (C++20)
(DR11)
Generación de definiciones de funciones y variables cuando se necesitan para evaluación constante
__cpp_constexpr_dynamic_alloc 201907L (C++20) Operaciones para duración de almacenamiento dinámico en constexpr functions
__cpp_constexpr 202306L (C++26) constexpr cast desde void * : hacia constexpr type-erasure
202406L (C++26) constexpr placement new y new [ ]
__cpp_constexpr_exceptions 202411L (C++26) constexpr exceptions: [1] , [2]

Ejemplo

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 94 C++98 las expresiones constantes aritméticas no podían
involucrar variables y miembros de datos estáticos
ahora pueden
CWG 366 C++98 las expresiones que involucran literales de cadena
podrían ser expresiones constantes integrales
no lo son
CWG 457 C++98 las expresiones que involucran variables volatile
podían ser expresiones constantes integrales
no lo son
CWG 1293 C++11 no estaba claro si los literales de cadena
son utilizables en expresiones constantes
son utilizables
CWG 1311 C++11 Los valores-gl volatile podían usarse en expresiones constantes prohibido
CWG 1312 C++11 reinterpret_cast está prohibido en expresiones constantes,
pero la conversión hacia y desde void * podría lograr el mismo efecto
conversiones prohibidas
desde el tipo cv void * hacia
un tipo puntero-a-objeto
CWG 1313 C++11 se permitía comportamiento indefinido;
se prohibía toda resta de punteros
Comportamiento indefinido prohibido; resta de
punteros del mismo arreglo permitida
CWG 1405 C++11 para objetos que son utilizables en expresiones constantes,
sus subobjetos mutables también eran utilizables
no son utilizables
CWG 1454 C++11 pasar constantes a través de funciones constexpr
mediante referencias no estaba permitido
permitido
CWG 1455 C++11 las expresiones constantes convertidas solo podían ser prvalues pueden ser lvalues
CWG 1456 C++11 una expresión constante de dirección no podía
designar la dirección uno más allá del final de un array
permitido
CWG 1535 C++11 una typeid expresión cuyo operando es de un
tipo de clase polimórfica no era una expresión constante
del núcleo incluso si no se involucraba ninguna verificación en tiempo de ejecución
la restricción del operando
se limita a glvalues de
tipos de clase polimórficos
CWG 1581 C++11 las funciones necesarias para evaluación constante
no se requería que estuvieran definidas o instanciadas
requerido
CWG 1613 C++11 las expresiones constantes principales podían evaluar cualquier
referencia odr-usada dentro de expresiones lambda
algunas referencias no podían
ser evaluadas
CWG 1694 C++11 vincular el valor de un temporal a una referencia de duración de almacenamiento
estática era una expresión constante
no es una
expresión constante
CWG 1872 C++11 las expresiones constantes principales podían invocar constexpr instanciaciones de plantillas de función
que no cumplían con los requisitos de función constexpr
dichas instanciaciones
no pueden ser invocadas
CWG 1952 C++11 comportamientos indefinidos de la biblioteca estándar
debían ser diagnosticados
no especificado si
son diagnosticados
CWG 2022 C++98 la determinación de expresión constante podría
depender de si se realiza la elisión de copia
asumir que la elisión de copia
siempre se realiza
CWG 2126 C++11 los temporales con inicialización constante y extensión de vida útil de tipos literales calificados como const
no eran utilizables en expresiones constantes
utilizable
CWG 2129 C++11 los literales enteros no eran expresiones constantes sí lo son
CWG 2167 C++11 referencias no miembro locales a una evaluación
hicieron la evaluación no constexpr
referencias no miembro
permitidas
CWG 2278 C++98 la resolución de CWG issue 2022 no era implementable asumir que la elisión de copia
nunca se realiza
CWG 2299 C++14 no estaba claro si las macros en <cstdarg>
pueden usarse en evaluación constante
va_arg prohibido,
va_start no especificado
CWG 2400 C++11 invocar una función virtual constexpr en un objeto no utilizable
en expresiones constantes y cuya vida útil comenzó fuera de la
expresión que contiene la invocación podría ser una expresión constante
no es una
expresión constante
CWG 2490 C++20 Las llamadas a (pseudo) destructores carecían de
restricciones en evaluación constante
restricción añadida
CWG 2552 C++23 al evaluar una expresión constante del núcleo, el flujo de control
no podía pasar a través de una declaración de una variable no de bloque
puede hacerlo
CWG 2558 C++11 un valor indeterminado podría ser una expresión constante no es una expresión constante
CWG 2647 C++20 las variables de tipos calificados como volátiles podrían ser potencialmente constantes no lo son
CWG 2763 C++11 la violación de [[ noreturn ]] no se requería
detectar durante la evaluación constante
requerido
CWG 2851 C++11 las expresiones constantes convertidas no
permitían conversiones de punto flotante
permitir conversiones de punto flotante
que no sean de estrechamiento
CWG 2907 C++11 las expresiones constantes principales no podían aplicar
conversiones de lvalue a rvalue a std::nullptr_t glvalues
pueden aplicar dichas
conversiones
CWG 2909 C++20 una variable sin un inicializador solo podría ser
inicializada constantemente si su inicialización por defecto
resulta en alguna inicialización siendo realizada
solo puede ser inicializada
constantemente si su tipo es
const-default-initializable
CWG 2924 C++11
C++23
no estaba especificado si una expresión que viola
las restricciones de [[ noreturn ]] (C++11) o
[[ assume ]] (C++23) es una expresión constante principal
es
definido por la implementación
P2280R4 C++11 evaluar una expresión que contiene una expresión de identificador
o * this que se refiere a un objeto o referencia cuyo tiempo de vida
comenzó fuera de esta evaluación no es una expresión constante
puede ser una
expresión constante

Véase también

constexpr especificador (C++11) especifica que el valor de una variable o función puede calcularse en tiempo de compilación
(C++11) (obsoleto en C++17) (eliminado en C++20)
verifica si un tipo es un tipo literal
(plantilla de clase)
Documentación C para Expresiones constantes