A bit of background.
I wrote a game engine for a long time. It is divided into several static libraries, such as "utils", "rsbin" (resource system), "window", which are then linked into a single executable file.
This is a cross-platform engine compiled for Windows and Android. On Windows, I compile it using MinGW. On Android, with CCTools, which is the interface for the native gcc.
One of the base classes is utils::RefObject , which is a concept similar to Windows IUnknown: it provides a reference counter to determine its lifetime and a method for requesting a specific interface from the base class pointer. There is also template< typename T > utils::Ref , designed specifically for such objects. It contains std::atomic< utils::RefObject* > and automatically updates its std::atomic< utils::RefObject* > object when building, assigning and destroying, similar to std::shared_ptr . It also allows you to implicitly convert RefObjects of various types using its query methods. Although, it is inefficient to query an object for its own type, therefore utils::Ref overloads most of its operators, e. d. there is a concrete constructor utils::Ref< T >::Ref( T* ptr ) , which simply increases the conversion factor of the passed object and the general utils::Ref< T >::Ref( RefObject* ptr ) , which asks for its argument for example, T throws an exception on failure (do not worry, although, of course, there is a method for soft cast).
But having only these two methods creates a problem: you cannot explicitly initialize utils::Ref null pointer, since it is ambiguous; therefore there is also utils::Ref< T >::Ref( nullptr_t ) to provide a way to do this.
Now we are facing a problem. In the header file, the prototype is written in exactly the same way as above, without the previous std:: . Please note that I do not use using namespace . It worked for a long time.
Now I am working on a graphics system. It existed before, but it was rather rudimentary, so I did not even notice that <gl.h> actually defines only OpenGL 1.1, while for newer versions you should go through <glext.h>. Now it has become necessary to use the latter. But also he broke the old reference class.
Judging by the error messages, MinGW now has problems with this nullptr_t in prototypes. I did a quick search on the Internet and found that it is often called std::nullptr_t . Although not everywhere.
Quick conclusion: I had nullptr_t without std:: or using namespace compilation until I included <glext.h> before the header.
The site I have used so far, cplusplus.com/reference, suggests that the global ::nullptr_t should be exactly the same . On the other hand, the en.cppreference.com wiki reports that std::nullptr_t .
The quick test program, helloworld with void foo( int ) and void foo( nullptr_t ) , could not be compiled, and the reason now is clearly "error: 'nullptr_t' was not declared in this scope" with a suggestion to use std::nullptr_t instead.
There is no need to add std:: where necessary; but this incident left me quite curious.
cplusplus.com actually lay? => Answered in commets, yes. This is an inaccurate source.
Then, if nullptr_t really in namespace std , why does utils::Ref compile? => With suggestions in the comments, I ran a couple of tests and found that <mutex> included in some other heading, when placed before any heading, stddef defines global ::nullptr_t . Of course, this is not ideal behavior, but it is not a serious mistake. Probably should report this to the MinGW / GCC developers.
Why does the inclusion of <glext.h> break it? => When the stddef header is included before <mutex>, the type is defined as std::nullptr_t according to the standard. <glext.h> includes <windows.h>, which, in turn, certainly includes the stddef header, among the entire package of others that are necessary for WinAPI.
Here are the sources defining the class in question:
(the last 2 are included and may also affect)
As suggested in the comments, I ran g ++ -E in a test case, which compiled, and found a rather interesting bit in <stddef.h>:
#if defined(__cplusplus) && __cplusplus >= 201103L #ifndef _GXX_NULLPTR_T #define _GXX_NULLPTR_T typedef decltype(nullptr) nullptr_t; #endif #endif
Now, to find where _GXX_NULLPTR_T defined different ... quick GREP through MinGW files did not find anything other than this stddef.h
So, itβs still a mystery why and how she becomes disabled. Especially if you include only <stddef.h> and nothing else defines nullptr_t anywhere, despite the bit above.