nullptr_t驻留在哪里? [英] Where does nullptr_t reside?

查看:110
本文介绍了nullptr_t驻留在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一些史前史.

我已经写了很长时间的游戏引擎.它分为几个静态库,例如"utils","rsbin"(资源系统),"window",然后链接到一个可执行文件中.

I've been writing a game engine for quite some time. It's divided into several static libraries, like "utils", "rsbin" (resource system), "window", which are then linked into a single executable.

这是一个跨平台引擎,正在针对Windows和Android进行编译. 在Windows下,我使用MinGW进行编译.在Android下,使用CCTools,它是本机gcc的界面.

It is a crossplatform engine, being compiled for Windows and for Android. Under Windows, I compile it with MinGW. Under Android, with CCTools, which is an interface to native gcc.

基类之一是utils::RefObject,它表示类似于Windows的IUnknown的概念:它提供了一个确定其生存期的引用计数器,以及一种用于从基类指针中查询特定接口的方法.还有template< typename T > utils::Ref,专门为此类对象设计的.它拥有一个std::atomic< utils::RefObject* >,并在构造,分配和销毁后自动更新其对象的引用计数,类似于std::shared_ptr.它还允许通过其查询方法隐式转换不同类型的RefObject.虽然,查询对象的自身类型效率不高,所以utils::Ref重载了其大多数运算符,例如e. G.有一个特定的utils::Ref< T >::Ref( T* ptr )构造函数,该构造函数仅增加传递的对象的refcount,而一个普通的utils::Ref< T >::Ref( RefObject* ptr ),该查询为T实例查询其参数,并在失败时引发异常(不过,请放心,当然有一种方法可以强制转换).

One of the base classes is utils::RefObject, which represents a concept similar to Windows's IUnknown: it provides a reference counter to determine its lifetime and a method for querying a specific interface from base class pointer. There's also template< typename T > utils::Ref, designed specifically for this kind of objects. It holds an std::atomic< utils::RefObject* > and automatically updates its object's refcount upon construction, assignment and destruction, analogously to std::shared_ptr. It also allows to implicitly convert RefObjects of different types through their querying methods. Though, it's inefficient to query an object for its own type, so, utils::Ref overloads most of its operators, e. g. there's specific utils::Ref< T >::Ref( T* ptr ) constructor, which simply increments the passed object's refcount, and general utils::Ref< T >::Ref( RefObject* ptr ), which queries its argument for instance of T and throws an exception on failure (don't worry, though, there's of course a method for the soft cast).

但是只有这两种方法会带来一个问题:由于模棱两可,您无法使用空指针显式初始化utils::Ref;因此,还有utils::Ref< T >::Ref( nullptr_t )提供了一种实现方法.

But having just these two methods introduces a problem: you cannot explicitly initialize utils::Ref with a null pointer, as it is ambiguous; so there's also utils::Ref< T >::Ref( nullptr_t ) to provide a way to do it.

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

Now, we are getting to the problem at hand. In the header file, the prototype is spelled exactly as above, without any preceding std::. Note that I don't use using namespace either. For a long time, this worked.

现在,我正在研究图形系统.它以前存在过,但还很初级,所以我什至没有注意到< gl.h>实际上仅定义了OpenGL 1.1,而对于较新的版本,则应浏览< glext.h>.现在,有必要使用后者.但包括它破坏了旧的参考类.

Now, I'm working on a graphics system. It existed before, but it was rather rudimentary, so I didn't even noticed that <gl.h> actually defines only OpenGL 1.1, while for newer versions you should go through <glext.h>. Now, it became necessary to use the latter. But including it broke the old reference class.

从错误消息来看,MinGW现在在原型中的nullptr_t存在问题.我在网上进行了快速搜索,发现经常被称为std::nullptr_t.不过,并非到处都是.

Judging from error messages, MinGW now has problems with that nullptr_t in prototypes. I've done a quick search on the Web and found that often it's referred to as std::nullptr_t. Though, not everywhere.

快速总结:在没有std::using namespace的情况下,我可以使用nullptr_t进行编译,直到我将< glext.h>包括在内.在标题之前.

Quick sumup: I had nullptr_t without either std:: or using namespace compiling fine until I included <glext.h> before the header.

到目前为止,我一直在使用的网站cplusplus.com/reference表示全局::nullptr_t 告诉我们实际上是.

The site I've been using so far, cplusplus.com/reference, suggests that global ::nullptr_t is exactly how it should be. On the other hand, en.cppreference.com wiki tells that it's actually std::nullptr_t.

一个快速测试程序,一个具有void foo( int )void foo( nullptr_t )的helloworld,未能编译,并且现在的原因是明确的"error: 'nullptr_t' was not declared in this scope"并建议使用std::nullptr_t.

A quick test program, a helloworld with void foo( int ) and void foo( nullptr_t ), failed to compile and the reason now is explicit "error: 'nullptr_t' was not declared in this scope" with suggestion to use std::nullptr_t instead.

在需要的地方添加std::并不困难;但是这种情况让我颇为好奇.

It won't be hard to add std:: where needed; but this case left me rather curious.

cplusplus.com实际上是在说谎吗? =>以逗号回答,是的.来源不正确.

cplusplus.com was actually lying? => Answered in commets, yes. It's an inaccurate source.

然后,如果nullptr_t实际上驻留在namespace std中,为什么utils::Ref可以编译? =>通过注释中的建议,进行了几次测试,发现包含在其他某些标头中的< mutex>当放置在任何stddef标头之前时,定义了全局::nullptr_t.当然不是理想的行为,但这不是主要的错误.无论如何,应该将其报告给MinGW/GCC开发人员.

Then, if nullptr_t actually resides in namespace std, why did utils::Ref compile? => With suggestions in comments, ran a couple of test and discovered that <mutex>, included in some other header, when placed before any stddef header, defines global ::nullptr_t. Certainly not an ideal behavior, but it's not a major bug. Probably should report it to MinGW/GCC developers anyway.

为什么要包含< glext.h>坏了吗? =>如果在< mutex>之前包含任何stddef标头,则根据标准将类型定义为std::nullptr_t. < glext.h>包括< windows.h> ;,它当然也包括stddef标头,以及WinAPI所需的其他完整包.

Why inclusion of <glext.h> breaks it? => When any stddef header is included before <mutex>, the type is defined according to the standard, as std::nullptr_t. <glext.h> includes <windows.h>, which, in turn, certainly includes the stddef header, among with a whole pack of others which are needed for WinAPI.

以下是定义所涉及类的来源:

Here are the sources, defining the class in question:

  • utils/ref.hpp
  • utils/ref.cpp
  • utils/refobject.hpp
  • utils/refobject.cpp
  • utils/logger.hpp => This one uses a mutex to avoid line tearing during output.
  • utils/cbase.hpp

(包括后2个,因此可能也会影响)

(the latter 2 are included and so may affect too)

正如评论中建议的那样,我在编译的测试用例上运行g ++ -E,并在< stddef.h>中找到了一个非常有趣的地方:

As suggested in the comments, I ran g++ -E on a test case which compiled, and found a quite 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 /* C++11.  */

现在要查找在其他地方定义了_GXX_NULLPTR_T的地方...通过MinGW的文件进行的快速GREP除了此stddef.h之外什么都找不到.

Now to find where _GXX_NULLPTR_T is defined else... a quick GREP through MinGW's files didn't find anything besides this stddef.h

因此,为什么以及如何使其禁用仍然是一个谜.特别是当仅包括< stddef.h>时,除了上述内容,没有其他地方在任何地方都没有定义nullptr_t.

So, it's still a mystery why and how it's getting disabled. Especially when including just <stddef.h> and nothing else does not define nullptr_t anywhere, despite the bit above.

推荐答案

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

The type of nullptr is defined in namespace ::std, so the correct qualification is ::std::nullptr_t. Of course, this means you normally spell it std::nullptr_t in practice.

引用C ++ 11:

2.14.7/1:

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

The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t.

18.2/9:

nullptr_t的定义如下:

namespace std {
  typedef decltype(nullptr) nullptr_t;
}

nullptr_t是同义词的类型具有在3.9.1和4.10中描述的特征. [注意: 尽管无法获取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>,因此这是定义了std::nullptr_t的C ++标头.根据D.5/2:

<stddef.h> also enters into the picture. 18.2 talks about <cstddef>, so that's the C++ header where std::nullptr_t is defined. Per D.5/2:

每个C头文件,每个文件头的名称格式均为name.h,其行为就像在标准中放置的每个名称一样. 相应的cname标头中的库名称空间放置在全局名称空间范围内.

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头文件,所以我建议不要在C ++代码中依赖它(即使它在形式上是有效的).

Which means that including <stddef.h> gives you access to ::nullptr_t. But since that's supposed to be a C header, I would advise against relying on this in C++ code (even if it's formally valid).

这篇关于nullptr_t驻留在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆