nullptr_t在哪里?

时间:2015-02-24 13:01:11

标签: c++ c++11 std nullptr

有点史前史。

我已经写了很长一段时间了。它分为几个静态库,如“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会使其大多数运算符重载,例如: G。有特定的utils::Ref< T >::Ref( T* ptr )构造函数,它只是递增传递的对象的引用计数,而通用utils::Ref< T >::Ref( RefObject* ptr ),它查询其参数为T的例子并在失败时抛出异常(不要担心,但是,当然一种软铸的方法。)

但是只有这两个方法引入了一个问题:你不能用空指针显式初始化utils::Ref,因为它是不明确的;所以还有utils::Ref< T >::Ref( nullptr_t )提供了一种方法。

现在,我们正在解决手头的问题。在头文件中,原型拼写与上面完全相同,没有任何前面的std::。请注意,我也不使用using namespace。很长一段时间,这都有效。

现在,我正在研究图形系统。它之前存在,但它相当简陋,所以我甚至没有注意到&lt; gl.h&gt;实际上只定义了OpenGL 1.1,而对于较新的版本,你应该通过&lt; glext.h&gt;。现在,有必要使用后者。但包括它打破了旧的参考类。

从错误消息判断,MinGW现在在原型中遇到了nullptr_t的问题。我在网上快速搜索了一下,发现经常它被称为std::nullptr_t。虽然,并非无处不在。

快速总结:我没有nullptr_tstd::编译using namespace,直到我收录&lt; glext.h&gt;在标题之前。

我目前使用的网站cplusplus.com/reference建议全球::nullptr_t is exactly how it should be。另一方面,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实际上在撒谎? =&GT;回答是肯定的,是的。这是一个不准确的来源。

然后,如果nullptr_t实际上位于namespace std,为什么utils::Ref会编译? =&GT;根据评论中的建议,进行了一些测试并发现&lt; mutex&gt;,包含在其他标题中,当放在任何stddef标头之前时,定义全局::nullptr_t。当然不是一个理想的行为,但它不是一个主要的错误。无论如何,可能应该向MinGW / GCC开发人员报告。

为什么要包含&lt; glext.h&gt;打破它? =&GT;当在&lt; mutex&gt;之前包含任何stddef标头时,类型根据标准定义为std::nullptr_t。 &LT; glext.h&GT;包括&lt; windows.h&gt;,这反过来肯定包括stddef标题,以及WinAPI所需的一整套其他标题。

以下是定义相关课程的来源:

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

正如评论中所建议的,我在编译的测试用例上运行了g ++ -E,并在&lt; stddef.h&gt;中找到了一个非常有趣的位:

#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之外没有找到任何东西

所以,它仍然是一个谜,为什么以及它如何被禁用。特别是当只包括&lt; stddef.h&gt;除了上面的内容之外,其他任何地方都没有定义nullptr_t

1 个答案:

答案 0 :(得分:5)

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

引用C ++ 11:

2.14.7 / 1:

  

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

18.2 / 9:

  

nullptr_t定义如下:

namespace std {
  typedef decltype(nullptr) nullptr_t;
}
     

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

<stddef.h>也进入了画面。 18.2讨论<cstddef>,以便定义std::nullptr_t的C ++标题。每D.5 / 2:

  

每个C标头(每个标头都有name.h形式的名称,就像每个名称都放在标准中一样   相应的cname标头的库命名空间放在全局命名空间范围内。

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