有点史前史。
我写游戏引擎已经有一段时间了。它分为几个静态库,例如“utils”、“rsbin”(资源系统)、“window”,然后将它们链接到一个可执行文件中。
它是一个跨平台引擎,为 Windows 和 Android 编译。在 Windows 下,我用 MinGW 编译它。在Android下,用CCTools,这是一个原生gcc的接口。
其中一个基类是utils::RefObject
,它代表了一个类似于 Windows 的 IUnknown 的概念:它提供了一个引用计数器来确定它的生命周期,以及一个从基类指针查询特定接口的方法。还有template< typename T > utils::Ref
,专门为这种对象设计的。它持有一个std::atomic< utils::RefObject* >
并在构造、赋值和销毁时自动更新其对象的引用计数,类似于std::shared_ptr
. 它还允许通过查询方法隐式转换不同类型的 RefObject。但是,查询一个对象的自身类型效率低下,因此,utils::Ref
重载了它的大多数运算符,例如,有特定的utils::Ref< T >::Ref( T* ptr )
构造函数,它只是增加传递的对象的引用计数,并且一般utils::Ref< T >::Ref( RefObject* ptr )
,它查询 T 实例的参数并在失败时抛出异常(不过不用担心,当然有一种用于软转换的方法)。
但是只有这两种方法会带来一个问题:你不能utils::Ref
用空指针显式初始化,因为它是模棱两可的;所以也utils::Ref< T >::Ref( nullptr_t )
提供了一种方法来做到这一点。
现在,我们正在解决手头的问题。在头文件中,原型的拼写与上面完全相同,没有任何前面std::
的 . 请注意,我也不使用using namespace
。很长一段时间,这行得通。
现在,我正在研究图形系统。它以前存在,但还很初级,所以我什至没有注意到 <gl.h> 实际上只定义了 OpenGL 1.1,而对于较新的版本,您应该通过 <glext.h>。现在,有必要使用后者。但包括它打破了旧的参考类。
从错误消息来看,MinGW 现在nullptr_t
在原型中存在问题。我在网上进行了快速搜索,发现它通常被称为std::nullptr_t
. 虽然,并非无处不在。
快速总结:在标题之前包含 <gext.h> 之前,我nullptr_t
没有任何一个std::
或编译得很好。using namespace
到目前为止,我一直在使用的网站 cplusplus.com/reference 表明 global::nullptr_t
正是它应该的样子。另一方面,en.cppreference.com wiki告诉它实际上是std::nullptr_t
.
一个快速测试程序,一个带有void foo( int )
and的 helloworld void foo( nullptr_t )
,编译失败,现在的原因很明确"error: 'nullptr_t' was not declared in this scope"
,建议std::nullptr_t
改用。
std::
在需要的地方添加并不难;但是这个案子让我很好奇。
cplusplus.com 真的在撒谎吗?=> 在评论中回答,是的。这是一个不准确的来源。
那么,如果nullptr_t
实际驻留在 中namespace std
,为什么要utils::Ref
编译呢?=> 有了评论中的建议,运行了几个测试,发现 <mutex>,包含在其他一些标头中,当放置在任何 stddef 标头之前时,定义 global ::nullptr_t
。当然不是一个理想的行为,但它不是一个主要的错误。无论如何,可能应该将其报告给 MinGW/GCC 开发人员。
为什么包含 <gext.h> 会破坏它?=> 如果在 <mutex> 之前包含任何 stddef 标头,则类型根据标准定义,如std::nullptr_t
. <glext.h> 包括 <windows.h>,而后者当然也包括 stddef 标头,以及 WinAPI 所需的一整包其他标头。
以下是定义相关类的来源:
- 实用程序/ref.hpp
- 实用程序/ref.cpp
- 实用程序/refobject.hpp
- 实用程序/refobject.cpp
- utils/logger.hpp => 这个使用互斥锁来避免输出过程中的行撕裂。
- 实用程序/cbase.hpp
(包括后两个,因此也可能会影响)
正如评论中所建议的,我在一个编译的测试用例上运行了 g++ -E,并在 <stddef.h> 中发现了一个非常有趣的位:
#if defined(__cplusplus) && __cplusplus >= 201103L
#ifndef _GXX_NULLPTR_T
#define _GXX_NULLPTR_T
typedef decltype(nullptr) nullptr_t;
#endif
#endif /* C++11. */
现在要查找_GXX_NULLPTR_T
其他定义的位置...通过 MinGW 文件的快速 GREP 没有找到除了这个 stddef.h 之外的任何内容
因此,它为什么以及如何被禁用仍然是一个谜。尤其是当只包含 <stddef.h> 并且没有其他任何东西没有定义nullptr_t
任何地方时,尽管上面有一点。