¿Dónde reside nullptr_t?

Un poco de prehistoria.

He estado escribiendo un motor de juego durante bastante tiempo. Se divide en varias bibliotecas estáticas, como "utils", "rsbin" (sistema de recursos), "ventana", que luego se vinculan en un solo ejecutable.

Es un motor multiplataforma, que se está compilando para Windows y para Android. En Windows, lo compilo con MinGW. En Android, con CCTools, que es una interfaz para gcc nativo.

Una de las clases base esutils::RefObject, que representa un concepto similar al IUnknown de Windows: proporciona un contador de referencia para determinar su duración y un método para consultar una interfaz específica desde el puntero de la clase base. También haytemplate< typename T > utils::Ref, diseñado específicamente para este tipo de objetos. Tiene unastd::atomic< utils::RefObject* > y actualiza automáticamente el recuento de su objeto tras la construcción, asignación y destrucción, de forma análogastd::shared_ptr. También permite convertir implícitamente RefObjects de diferentes tipos a través de sus métodos de consulta. Sin embargo, es ineficiente consultar un objeto para su propio tipo, entonces,utils::Ref sobrecarga a la mayoría de sus operadores, e. sol. hay específicoutils::Ref< T >::Ref( T* ptr ) constructor, que simplemente incrementa el recuento del objeto pasado, y generalutils::Ref< T >::Ref( RefObject* ptr ), que consulta su argumento, por ejemplo, de T y arroja una excepción en caso de falla (sin embargo, no se preocupe, por supuesto, hay un método para el lanzamiento suave).

Pero tener solo estos dos métodos presenta un problema: no se puede inicializar explícitamenteutils::Ref con un puntero nulo, ya que es ambiguo; entonces también hayutils::Ref< T >::Ref( nullptr_t ) para proporcionar una manera de hacerlo.

Ahora, estamos llegando al problema en cuestión. En el archivo de encabezado, el prototipo se deletrea exactamente como arriba, sin ningún precedentestd::. Tenga en cuenta que no usousing namespace ya sea. Durante mucho tiempo, esto funcionó.

Ahora estoy trabajando en un sistema gráfico. Existía antes, pero era bastante rudimentario, por lo que ni siquiera me di cuenta de que <gl.h> en realidad define solo OpenGL 1.1, mientras que para las versiones más nuevas debería pasar por <glext.h>. Ahora, se hizo necesario usar este último. Pero incluirlo rompió la vieja clase de referencia.

A juzgar por los mensajes de error, MinGW ahora tiene problemas con esonullptr_t en prototipos. Hice una búsqueda rápida en la Web y descubrí quea menudo se le conoce comostd::nullptr_t. Aunque, no en todas partes.

Resumen rápido: tuvenullptr_t sin cualquierastd:: ousing namespace compilando bien hasta que incluí <glext.h> antes del encabezado.

El sitio que he estado usando hasta ahora, cplusplus.com/reference, sugiere que global::nullptr_t es exactamente como debería ser. Por otro lado, en.cppreference.com wikidice que en realidad esstd::nullptr_t.

Un programa de prueba rápida, un helloworld convoid foo( int ) yvoid foo( nullptr_t ), no se pudo compilar y el motivo ahora es explícito"error: 'nullptr_t' was not declared in this scope" con sugerencia de usostd::nullptr_t en lugar.

No será difícil agregarstd:: donde sea necesario; Pero este caso me dejó bastante curioso.

cplusplus.com realmente estaba mintiendo? => Respondido en commets, sí. Es una fuente inexacta.

Entonces sínullptr_t en realidad reside ennamespace std, Por quéutils::Ref ¿compilar? => Con sugerencias en los comentarios, ejecuté un par de pruebas y descubrí que <mutex>, incluido en algún otro encabezado, cuando se coloca antes de cualquier encabezado stddef, define global::nullptr_t. Ciertamente no es un comportamiento ideal, pero no es un error importante. Probablemente debería informarlo a los desarrolladores de MinGW / GCC de todos modos.

¿Por qué la inclusión de <glext.h> lo rompe? => Cuando se incluye cualquier encabezado stddef antes de <mutex>, el tipo se define de acuerdo con el estándar, comostd::nullptr_t. <glext.h> incluye <windows.h>, que, a su vez, ciertamente incluye el encabezado stddef, junto con un paquete completo de otros que son necesarios para WinAPI.

Aquí están las fuentes, que definen la clase en cuestión:

utils / ref.hpputils / ref.cpputils / refobject.hpputils / refobject.cpputils / logger.hpp => Este usa un mutex para evitar el desgarro de línea durante la salida.utils / cbase.hpp

(los últimos 2 están incluidos y también pueden afectar)

Como se sugiere en los comentarios, ejecuté g ++ -E en un caso de prueba que se compiló, y encontré un bit bastante interesante en <stddef.h>:

#if defined(__cplusplus) && __cplusplus >= 201103L
#ifndef _GXX_NULLPTR_T
#define _GXX_NULLPTR_T
  typedef decltype(nullptr) nullptr_t;
#endif
#endif /* C++11.  */

Ahora para encontrar donde_GXX_NULLPTR_T se define de otra manera ... un GREP rápido a través de los archivos de MinGW no encontró nada además de este stddef.h

Entonces, sigue siendo un misterio por qué y cómo se desactiva. Especialmente cuando se incluye solo <stddef.h> y nada más no definenullptr_t en cualquier lugar, a pesar del bit de arriba.

Respuestas a la pregunta(1)

Su respuesta a la pregunta