c++ - dev - clang vs gcc
¿Es nullptr_t un tipo constructible por defecto? (2)
No puedo decir del estándar C ++ 11 si nullptr_t tiene un constructor predeterminado. En otras palabras, ¿es válido lo siguiente ?:
nullptr_t n;
GCC y VC ++ permiten el código anterior, pero clang no lo hace. No puedo encontrar nada en el Estándar que especifique que no tenga un constructor predeterminado, y lo que puedo encontrar sugiere que debería hacerlo. Esto me importa porque estoy escribiendo una implementación básica alternativa de nullptr para el soporte del compilador anterior y necesito saber si necesito darle un constructor predeterminado.
Lo que dice la norma
La norma dice (18.2)
nullptr_t se define de la siguiente manera:
namespace std { typedef decltype(nullptr) nullptr_t; }
El tipo para el que nullptr_t es un sinónimo tiene las características descritas en 3.9.1 y 4.10.
Donde 3.9.1 básicamente dice que debe ser del mismo tamaño que void*
y 4.10 especifica las reglas de conversión para nullptr
.
Edit: 3.9.9 además, explícitamente establece que nullptr_t
es un tipo escalar, lo que significa que se aplican las reglas de inicialización esperadas para los tipos incorporados de 8.5:
- Default-initialization (
nullptr_t n;
), que deja el valor den
indefinido. Como Johannes Schaub señaló correctamente, esto compila bien con la versión más reciente de Clang. - Inicialización del valor (
nullptr_t n = nullptr_t();
), que inicializa n a 0.
Este comportamiento es idéntico a, por ejemplo, int
, por lo que nullptr_t
es definitivamente construible por defecto. La pregunta interesante aquí es: ¿Qué significa que nullptr_t
tenga un valor indefinido? Al final del día, solo hay un valor significativo significativo para nullptr_t
, que es nullptr
. Además, el tipo en sí solo se define a través de la semántica del literal nullptr
. ¿Estas semánticas todavía aplican para un valor unitario?
Por qué esa pregunta no importa en la práctica
No desea declarar una nueva variable de tipo nullptr_t
. La única semántica significativa de ese tipo ya se expresa a través del literal nullptr
, por lo que cada vez que use su variable personalizada de tipo nullptr_t
, también puede usar nullptr
.
Lo que importa en la práctica.
La única excepción a esto proviene del hecho de que puede tomar parámetros de plantilla que no sean de tipo nullptr_t
. Para este caso, es útil saber qué valores se pueden convertir a nullptr_t
, que se describe en 4.10:
Una constante de puntero nula es una expresión constante constante (5.19) prvalue de tipo entero que se evalúa a cero o un prvalue de tipo
std::nullptr_t
. [...] Una constante de puntero nulo de tipo integral se puede convertir a un valor predeterminado de tipostd::nullptr_t
.
Lo que básicamente hace justo lo que esperas: puedes escribir
nullptr_t n = 0; // correct: 0 is special
pero no
nullptr_t n = 42; // WRONG can''t convert int to nullptr_t
Tanto gcc 4.6 como Clang SVN lo hacen bien.
Si bien nullptr
es una nueva adición al lenguaje en sí, std::nullptr_t
es solo un alias de un tipo sin nombre, el alias declarado en cstddef
esta manera:
typedef decltype(nullptr) nullptr_t;
Si bien nullptr_t
, siendo typedef y no una palabra clave de idioma, no aparece como un tipo fundamental, se especifica que se comporte como un tipo fundamental (y no, por ejemplo, como un tipo de puntero o un tipo de clase). Por lo tanto, no tiene un constructor predeterminado, pero aún puede declarar una variable como lo ha hecho. Su variable no está inicializada y me pregunto qué uso podría tener y qué mensaje de error recibió exactamente de clang
.
Véase también here .