nullptr_t在哪里?

Del*_*mer 6 c++ std nullptr c++11

有点史前史.

我已经写了很长一段时间了.它分为几个静态库,如"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 )构造函数,它只是递增传递的对象的引用计数,而general 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.虽然,并非无处不在.

快速总结:直到我在标题之前包含<glext.h>之前,我nullptr_t没有编译std::using namespace编译正常.

到目前为止,我一直在使用的网站cplusplus.com/reference表明,全球化::nullptr_t 应该是应该如何.另一方面,en.cppreference.com wiki 告诉它实际上std::nullptr_t.

一个快速测试程序,一个带有void foo( int )和的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标头之前,定义全局::nullptr_t.当然不是一个理想的行为,但它不是一个主要的错误.无论如何,可能应该向MinGW/GCC开发人员报告.

为什么包含<glext.h>打破了它?=>当在<mutex>之前包含任何stddef头时,类型根据标准定义,如std::nullptr_t.<glext.h>包括<windows.h>,它反过来肯定包含stddef头文件,其中包含WinAPI所需的一整套其他文件.

以下是定义相关类的来源:

(后两者包括在内,因此也可能影响)

正如评论中所建议的,我在编译的测试用例上运行了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.  */
Run Code Online (Sandbox Code Playgroud)

现在找到_GXX_NULLPTR_T其他定义的地方...快速GREP通过MinGW的文件除了这个stddef.h之外没有找到任何东西

因此,它仍然是一个谜,为什么以及它如何被禁用.特别是在包含<stddef.h>时,没有其他nullptr_t任何地方没有定义,尽管有点上面.

Rei*_*ica 5

类型nullptr是在命名空间中定义的::std,因此正确的限定条件是::std::nullptr_t.当然,这意味着你通常std::nullptr_t在实践中拼写它.

引用C++ 11:

2.14.7/1:

指针文字是关键字nullptr.它是一种类型的prvalue std::nullptr_t.

18.2/9:

nullptr_t 定义如下:

namespace std {
  typedef decltype(nullptr) nullptr_t;
}
Run Code Online (Sandbox Code Playgroud)

其类型nullptr_t是同义词,具有3.9.1和4.10中描述的特征.[ 注意: 虽然nullptr不能使用地址,但可以采用另一个nullptr_t左值的对象的地址.- 尾注 ]

<stddef.h>也进入了画面.18.2讨论<cstddef>,所以这std::nullptr_t是定义的C++头.每D.5/2:

每个C头(每个头都有一个表单的名称)的name.h行为就好像每个由相应cname头放在标准库命名空间中的名称放在全局命名空间范围内.

这意味着包括<stddef.h>让您访问::nullptr_t.但是因为那应该是一个C头,我建议不要在C++代码中依赖它(即使它正式有效).