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 denindefinido. 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 .