nullptr_t住在哪里?
Where does nullptr_t reside?
有点史前史。
我编写游戏引擎已经有一段时间了。它分为几个静态库,如 "utils"、"rsbin"(资源系统)、"window",然后链接到一个可执行文件中。
它是一个跨平台引擎,正在为 Windows 和 Android 编译。
在Windows下,我是用MinGW编译的。在 Android 下,使用 CCTools,它是原生 gcc 的接口。
其中一个基础classes是utils::RefObject
,它代表了一个类似于Windows的IUnknown的概念:它提供了一个引用计数器来确定它的生命周期和一个方法从基 class 指针查询特定接口。还有专门为这种object设计的template< typename T > utils::Ref
。它持有一个 std::atomic< utils::RefObject* >
并在构造、分配和销毁时自动更新其 object 的引用计数,类似于 std::shared_ptr
。它还允许通过查询方法隐式转换不同类型的 RefObjects。但是,查询 object 自身类型的效率很低,因此 utils::Ref
重载了它的大部分运算符,例如。 G。有特定的 utils::Ref< T >::Ref( T* ptr )
构造函数,它简单地增加传递的 object 的引用计数,和通用的 utils::Ref< T >::Ref( RefObject* ptr )
,它查询它的参数以获取 T 的实例并在失败时抛出异常(不用担心,虽然,当然有一个软演员的方法)。
但是只有这两种方法会引入一个问题:您不能使用空指针显式初始化 utils::Ref
,因为它是不明确的;所以还有 utils::Ref< T >::Ref( nullptr_t )
提供了一种方法。
现在,我们开始解决手头的问题。在 header 文件中,原型的拼写与上面完全相同,前面没有任何 std::
。请注意,我也不使用 using namespace
。很长一段时间以来,这都奏效了。
现在,我正在研究图形系统。它以前就存在,但它相当简陋,所以我什至没有注意到 实际上只定义了 OpenGL 1.1,而对于较新的版本,你应该通过 。现在,有必要使用后者。但包括它打破了旧参考 class.
从错误消息来看,MinGW 现在在原型中存在 nullptr_t
的问题。我在网上快速搜索了一下,发现 通常 它被称为 std::nullptr_t
。虽然,不是到处都是。
快速总结:我有 nullptr_t
而没有 std::
或 using namespace
编译正常,直到我在 [=130 之前包含 =].
到目前为止我一直在使用的站点cplusplus.com/reference,建议global ::nullptr_t
is exactly how it should be. On the other hand, en.cppreference.com wiki tells that 实际上是std::nullptr_t
.
一个快速测试程序,一个带有 void foo( int )
和 void foo( nullptr_t )
的 helloworld,编译失败,现在的原因很明确 "error: 'nullptr_t' was not declared in this scope"
,建议改用 std::nullptr_t
。
在需要的地方添加std::
并不难;但是这个案例让我很好奇。
cplusplus.com居然在撒谎? => 在评论中回答,是的。这是一个不准确的来源。
那么,如果nullptr_t
实际上驻留在namespace std
,为什么utils::Ref
编译呢? => 根据评论中的建议,运行 一些测试发现 包含在其他一些 header 中,当放置在任何 stddef header 之前时,定义了全局 ::nullptr_t
.当然不是理想的行为,但这不是主要错误。无论如何,可能应该将其报告给 MinGW/GCC 开发人员。
为什么包含 会破坏它? => 当在 之前包含任何 stddef header 时,类型根据标准定义为 std::nullptr_t
。 包括 ,后者当然包括 stddef header,以及 WinAPI 所需的一整套其他内容。
这里是来源,定义了有问题的 class:
- utils/ref.hpp
- utils/ref.cpp
- utils/refobject.hpp
- utils/refobject.cpp
- utils/logger.hpp => 这个使用互斥量来避免输出过程中的行撕裂。
- utils/cbase.hpp
(包括后两个,因此也可能影响)
正如评论中所建议的,我 运行 g++ -E 在编译的测试用例上,并在 :
中发现了一个非常有趣的位
#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
之外的任何内容
因此,为什么以及如何禁用它仍然是个谜。尤其是当只包含 并且没有其他任何东西都没有定义 nullptr_t
时,尽管上面有一点。
nullptr
的类型在命名空间 ::std
中定义,因此正确的限定是 ::std::nullptr_t
。当然,这意味着您通常会在练习中拼写 std::nullptr_t
。
引用 C++11:
2.14.7/1:
The pointer literal is the keyword nullptr
. It is a prvalue of type std::nullptr_t
.
18.2/9:
nullptr_t
is defined as follows:
namespace std {
typedef decltype(nullptr) nullptr_t;
}
The type for which nullptr_t
is a synonym has the characteristics described in 3.9.1 and 4.10. [ Note:
Although nullptr
’s address cannot be taken, the address of another nullptr_t
object that is an lvalue can
be taken. —end note ]
<stddef.h>
也进入画面。 18.2讲的是<cstddef>
,所以就是C++header里面定义了std::nullptr_t
。根据 D.5/2:
Every C header, each of which has a name of the form name.h
, behaves as if each name placed in the standard
library namespace by the corresponding cname
header is placed within the global namespace scope.
这意味着包含 <stddef.h>
可以让您访问 ::nullptr_t
。但是因为那应该是 C header,我建议不要在 C++ 代码中依赖它(即使它在形式上是有效的)。
有点史前史。
我编写游戏引擎已经有一段时间了。它分为几个静态库,如 "utils"、"rsbin"(资源系统)、"window",然后链接到一个可执行文件中。
它是一个跨平台引擎,正在为 Windows 和 Android 编译。 在Windows下,我是用MinGW编译的。在 Android 下,使用 CCTools,它是原生 gcc 的接口。
其中一个基础classes是utils::RefObject
,它代表了一个类似于Windows的IUnknown的概念:它提供了一个引用计数器来确定它的生命周期和一个方法从基 class 指针查询特定接口。还有专门为这种object设计的template< typename T > utils::Ref
。它持有一个 std::atomic< utils::RefObject* >
并在构造、分配和销毁时自动更新其 object 的引用计数,类似于 std::shared_ptr
。它还允许通过查询方法隐式转换不同类型的 RefObjects。但是,查询 object 自身类型的效率很低,因此 utils::Ref
重载了它的大部分运算符,例如。 G。有特定的 utils::Ref< T >::Ref( T* ptr )
构造函数,它简单地增加传递的 object 的引用计数,和通用的 utils::Ref< T >::Ref( RefObject* ptr )
,它查询它的参数以获取 T 的实例并在失败时抛出异常(不用担心,虽然,当然有一个软演员的方法)。
但是只有这两种方法会引入一个问题:您不能使用空指针显式初始化 utils::Ref
,因为它是不明确的;所以还有 utils::Ref< T >::Ref( nullptr_t )
提供了一种方法。
现在,我们开始解决手头的问题。在 header 文件中,原型的拼写与上面完全相同,前面没有任何 std::
。请注意,我也不使用 using namespace
。很长一段时间以来,这都奏效了。
现在,我正在研究图形系统。它以前就存在,但它相当简陋,所以我什至没有注意到
从错误消息来看,MinGW 现在在原型中存在 nullptr_t
的问题。我在网上快速搜索了一下,发现 通常 它被称为 std::nullptr_t
。虽然,不是到处都是。
快速总结:我有 nullptr_t
而没有 std::
或 using namespace
编译正常,直到我在 [=130 之前包含
到目前为止我一直在使用的站点cplusplus.com/reference,建议global ::nullptr_t
is exactly how it should be. On the other hand, en.cppreference.com wiki tells that 实际上是std::nullptr_t
.
一个快速测试程序,一个带有 void foo( int )
和 void foo( nullptr_t )
的 helloworld,编译失败,现在的原因很明确 "error: 'nullptr_t' was not declared in this scope"
,建议改用 std::nullptr_t
。
在需要的地方添加std::
并不难;但是这个案例让我很好奇。
cplusplus.com居然在撒谎? => 在评论中回答,是的。这是一个不准确的来源。
那么,如果nullptr_t
实际上驻留在namespace std
,为什么utils::Ref
编译呢? => 根据评论中的建议,运行 一些测试发现 ::nullptr_t
.当然不是理想的行为,但这不是主要错误。无论如何,可能应该将其报告给 MinGW/GCC 开发人员。
为什么包含 std::nullptr_t
。
这里是来源,定义了有问题的 class:
- utils/ref.hpp
- utils/ref.cpp
- utils/refobject.hpp
- utils/refobject.cpp
- utils/logger.hpp => 这个使用互斥量来避免输出过程中的行撕裂。
- utils/cbase.hpp
(包括后两个,因此也可能影响)
正如评论中所建议的,我 运行 g++ -E 在编译的测试用例上,并在
#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
因此,为什么以及如何禁用它仍然是个谜。尤其是当只包含 nullptr_t
时,尽管上面有一点。
nullptr
的类型在命名空间 ::std
中定义,因此正确的限定是 ::std::nullptr_t
。当然,这意味着您通常会在练习中拼写 std::nullptr_t
。
引用 C++11:
2.14.7/1:
The pointer literal is the keyword
nullptr
. It is a prvalue of typestd::nullptr_t
.
18.2/9:
nullptr_t
is defined as follows:namespace std { typedef decltype(nullptr) nullptr_t; }
The type for which
nullptr_t
is a synonym has the characteristics described in 3.9.1 and 4.10. [ Note: Althoughnullptr
’s address cannot be taken, the address of anothernullptr_t
object that is an lvalue can be taken. —end note ]
<stddef.h>
也进入画面。 18.2讲的是<cstddef>
,所以就是C++header里面定义了std::nullptr_t
。根据 D.5/2:
Every C header, each of which has a name of the form
name.h
, behaves as if each name placed in the standard library namespace by the correspondingcname
header is placed within the global namespace scope.
这意味着包含 <stddef.h>
可以让您访问 ::nullptr_t
。但是因为那应该是 C header,我建议不要在 C++ 代码中依赖它(即使它在形式上是有效的)。