c++ c++11 chrono

c++ - ¿Cómo puede ser constexpr std:: chrono:: duration:: duration()?



c++11 (1)

7.1.5 El especificador constexpr [dcl.constexpr] dice:

La definición de un constructor constexpr deberá cumplir los siguientes requisitos:

  • la clase no tendrá ninguna clase base virtual;
  • para un constructor predeterminado de copiar / mover, la clase no tendrá un subobjeto mutable que sea un miembro variante;
  • cada uno de los tipos de parámetros será un tipo literal;
  • su función-body no será una función-try-block;

Además, su función-body será = delete, o cumplirá los siguientes requisitos:

  • o bien su función-cuerpo será = por defecto, o la declaración compuesta de su función-cuerpo deberá satisfacer los requisitos para una función-cuerpo de una función constexpr;
  • todo miembro no variante de datos no estáticos y subobjetos de clase base se inicializarán (12.6.2);
  • si la clase es una unión que tiene miembros variantes (9.5), se debe inicializar exactamente uno de ellos;
  • si la clase es una clase similar a una unión, pero no es una unión, para cada uno de sus miembros anónimos de la unión que tienen miembros variantes, se debe inicializar exactamente uno de ellos;
  • para un constructor no delegante, cada constructor seleccionado para inicializar miembros de datos no estáticos y subobjetos de clase base será un constructor constexpr;
  • para un constructor delegante, el constructor de destino será un constructor constexpr.

En pocas palabras, = default es una definición válida de un constructor por defecto constexpr siempre que se cumplan los otros requisitos anteriores.

Entonces, ¿cómo funciona esto con construcciones no inicializadas ?

No lo hace

Por ejemplo:

constexpr seconds x1{};

Lo anterior funciona e inicializa x1 a 0s . Sin embargo:

constexpr seconds x2; error: default initialization of an object of const type ''const seconds'' (aka ''const duration<long long>'') without a user-provided default constructor constexpr seconds x2; ^ {} 1 error generated.

Por lo tanto, para crear una duration construida predeterminada de constexpr , debe inicializarla con cero . Y la implementación = default permite inicializar a cero con {} .

Demo completa de trabajo:

template <class Rep> class my_duration { Rep rep_; public: constexpr my_duration() = default; }; int main() { constexpr my_duration<int> x{}; }

Barra lateral interesante

Aprendí algo al escribir esta respuesta, y quería compartir:

Me seguí preguntando por qué lo siguiente no funciona:

using Rep = int; class my_duration { Rep rep_; public: constexpr my_duration() = default; }; int main() { constexpr my_duration x{}; } error: defaulted definition of default constructor is not constexpr constexpr my_duration() = default; ^

¿Por qué hacer que esta clase sea una no-plantilla rompe el constructor predeterminado constexpr ?

Entonces intenté esto:

using Rep = int; class my_duration { Rep rep_; public: my_duration() = default; // removed constexpr }; int main() { constexpr my_duration x{}; }

Y a los compiladores les gusta otra vez.

Si todavía no hay un problema de CWG sobre esto, probablemente debería haberlo. El comportamiento parece un poco inconsistente. Y esto es probablemente porque nosotros (la industria entera) todavía estamos aprendiendo sobre constexpr .

El constructor predeterminado de std::chrono::duration se define de la siguiente manera:

constexpr duration() = default;

(Por ejemplo, vea cppreference.com o la fuente libstdc ++).

Sin embargo, cppreference.com también dice esto acerca de los constructores constexpr :

Un constructor constexpr debe cumplir los siguientes requisitos:

...

cada clase base y cada miembro no estático deben inicializarse , ya sea en la lista de inicialización de los constructores o por un miembro con inicializador de refuerzo o igual. Además, cada constructor involucrado debe ser un constructor constexpr y cada cláusula de cada inicializador de refuerzo o igual debe ser una expresión constante

Y en caso de que estuviera confundido acerca de los constructores predeterminados, cppreference.com parece decir que los constructores predeterminados creados con = default no se definen de manera diferente a los constructores predeterminados implícitos.

Sin embargo, el tipo de rep para (la mayoría) de las duraciones es un tipo entero desnudo. Entonces, ¿no debería el constructor por defecto explícito = default para la duration ser equivalente a

constexpr duration() {}

que, por supuesto, dejaría la variable miembro entero del tipo duration::rep uninitialized? Y, de hecho, ¿no es el comportamiento estándar de la duration tal que los valores construidos por defecto no están inicializados? (Pero no puedo encontrar una referencia que explícitamente diga esto).

Entonces, ¿cómo puede el constructor = default para la duration ser constexpr si deja una variable miembro no estática sin inicializar? ¿Qué me estoy perdiendo?