关于C++中的全局命名空间

发布于 2024-12-08 07:55:10 字数 227 浏览 0 评论 0原文

在 C++ 中,我们应该在全局命名空间中添加 :: 的内容吗?

例如,当使用 C 语言的 WinAPI 时,我应该用 ::HANDLE 而不是 HANDLE,用 ::LoadLibrary 而不是 <代码>加载库? C++ 对此有何评论?考虑到可读性和可维护性等问题,这通常是一个好主意吗?

In C++, should we be prepending stuff in the global namespace with ::?

For example, when using WinAPI, which is in C, should I do ::HANDLE instead of HANDLE, and ::LoadLibrary instead of LoadLibrary? What does C++ say about this? Is it generally a good idea, factoring in issues like readability and maintainability?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

与风相奔跑 2024-12-15 07:55:10

C++ 中的名称可以是限定的和非限定的。限定名称和非限定名称查找有不同的规则。 ::HANDLE 是限定名称,而 HANDLE 是非限定名称。考虑以下示例:

#include <windows.h>

int main()
{
    int HANDLE;
    HANDLE x; //ERROR HANDLE IS NOT A TYPE
    ::HANDLE y; //OK, qualified name lookup finds the global HANDLE
}

我认为选择 HANDLE::HANDLE 的决定是编码风格的问题。当然,正如我的例子所表明的,在某些情况下,资格赛是强制性的。因此,您不妨使用 :: 以防万一,除非语法对您来说有点恶心。

Names in C++ can be qualified and unqualified. There are different rules for qualified and unqualified name lookup. ::HANDLE is a qualified name, whereas HANDLE is an unqualified name. Consider the following example:

#include <windows.h>

int main()
{
    int HANDLE;
    HANDLE x; //ERROR HANDLE IS NOT A TYPE
    ::HANDLE y; //OK, qualified name lookup finds the global HANDLE
}

I think that the desicion of choosing HANDLE vs. ::HANDLE is a matter of coding style. Of course, as my example suggests, there might be situations where qualifying is mandatory. So, you might as well use :: just in case, unless the syntax is somewhat disgusting for you.

不弃不离 2024-12-15 07:55:10

由于 C 中不存在命名空间,因此不要使用 ::HANDLE 来访问 HANDLE 类型。

使用前缀 :: 作为全局命名空间是提高可读性的好主意,您知道要访问的类型来自全局命名空间。

此外,如果您位于嵌套命名空间中并声明自己的 HANDLE 类型(例如),那么编译器将使用此类型而不是 windows.h 类型!

因此,在嵌套命名空间中工作时,总是更喜欢在名称之前使用::。

As namespaces don't exists in C, don't use ::HANDLE to access HANDLE type.

Using the prepending :: for global namespace is a good idea for readability, you know the type you want to access is from global namespace.

Moreover, if you are in a nested namespace and declare your own HANDLE type (for example), then the compiler will use this one instead of windows.h one!

Thus, always prefer using :: before names when working in nested namespace.

紅太極 2024-12-15 07:55:10

主要的兴趣点是从编译器的角度来看差异是什么,正如已经说过的,如果您包含 :: 那么您将使用限定查找,而不是非限定查找。

使用限定查找的优点是它始终能够精确定位特定的符号。缺点是它总是会精确定位该特定符号——即它将禁用参数相关查找。 ADL 是该语言的一个重要且有用的部分,通过限定你可以有效地禁用它,这是很糟糕的。

假设您在全局命名空间中有一个函数 f,并且在命名空间 N 内添加了一个类型 T。不要考虑您想要添加以 T 作为参数的 f 重载。遵循接口原则,您可以将f添加到N命名空间,因为f实际上是对T,因此它属于该类型。在这种情况下,如果您的代码在未知类型 U 的对象上调用(考虑通用代码)::f(obj),编译器将无法选择将 ::N::f(obj) 作为潜在的重载,因为代码明确要求全局命名空间中的重载。

使用非限定查找可以让您自由地定义函数所属的位置以及用作参数的类型。虽然不完全相同,但请考虑使用 swap,如果您符合 std::swap 的条件,那么它将不会拾取您手卷的 void swap( T&, T& ) 在您的 N 命名空间中...

只有当编译器无法获取我想要的元素时,我才会完全限定标识符。

The main point of interest is what the differences are from the point of view of the compiler, as it has already been said, if you include the :: then you are using qualified lookup, rather than unqualified lookup.

The advantage of using qualified lookup is that it will be able to pinpoint a particular symbol always. The disadvantage is that it will always pinpoint that particular symbol --i.e. it will disable Argument Dependent Lookup. ADL is a big and useful part of the language, and by qualifying you effectively disable it, and that is bad.

Consider that you had a function f in the global namespace, and that you added a type T inside namespace N. Not consider that you wanted to add an overload of f that would take a T as argument. Following the interface principle, you can add f to the N namespace, as f is actually an operation performed on T, and it so belongs with the type. In this case, if you had code that called (consider generic code) ::f(obj) on an object of unknown type U the compiler will not be able to pick up ::N::f(obj) as a potential overload as the code is explicitly asking for an overload in the global namespace.

Using unqualified lookup gives you the freedom of defining the functions where they belong, together with the types that are used as arguments. While it is not exactly the same, consider the use of swap, if you qualify std::swap then it will not pick up your hand rolled void swap( T&, T& ) inside your N namespace...

I would only fully qualify identifiers when the compiler would otherwise not pick up the element I want.

日久见人心 2024-12-15 07:55:10

这很大程度上是风格问题。没有性能或效率问题可言。对于大型项目和打算在许多不同平台上编译的项目来说,这可能是一个很好的实践,因为在这些情况下,全局名称和命名空间中的名称之间更有可能发生冲突。

It's largely a matter of style; there are no performance or efficiency concerns to speak of. It can be a good practice on large projects and projects intended to be compiled on many different platforms, as under these circumstances collisions between global names and names in a namespace are more likely to occur.

几味少女 2024-12-15 07:55:10

通常,您不必必须为全局命名空间添加::。 (仅在某些非常罕见的情况下)。恕我直言,它会损害可读性,但是,另一方面,它可能不会破坏您的代码

Normally, you do not have to prepend :: for the global namespace. (Only in some really rare circumstances). IMHO it harms readability, but, on the other hand it probably won't break your code

热情消退 2024-12-15 07:55:10

我将所有代码放入一个命名空间中,并且相对于 C 标头,我更喜欢使用 C++ 标头,因此全局命名空间中留下的唯一符号往往来自 Windows API。我避免将符号从其他命名空间拉入当前命名空间(例如,我从来没有使用命名空间 std; ),而是更喜欢显式地限定事物。这符合 Google 的 C++ 风格指南

因此,我养成了使用 :: 限定 WinAPI 函数调用的习惯,原因如下:

  1. 一致性。对于当前命名空间之外的所有内容,我显式引用它(例如,std::string),那么为什么不显式引用 Windows API(例如,::LoadLibraryW )? Windows API 命名空间全局命名空间。

  2. 许多 WinAPI 函数都是通用命名的(例如,DeleteObject)。除非您非常熟悉正在阅读的代码,否则您可能不知道 DeleteObject 是对当前命名空间中的某些内容的调用还是对 Windows API 的调用。因此,我发现 :: 澄清了。

  3. 许多 Windows 框架都有与原始调用同名的方法。例如,ATL::CWindow 有一个 GetClientRect 方法,其签名与 WinAPI 的 GetClientRect 略有不同。在此框架中,您的类通常从 ATL::CWindow 派生,因此,在您的类的实现中,通常会使用 GetClientRect 来调用继承的 ATL 方法如果您需要调用 WinAPI 函数,则使用 ::GetClientRect 。这并不是绝对必要的,因为编译器会根据签名找到正确的签名。尽管如此,我发现读者可以清楚地了解其中的区别。

(我知道这个问题实际上并不是关于 WinAPI,但这个例子是关于 WinAPI 的。)

I put all of my code into a namespace, and I tend to prefer the C++ headers over the C headers, so the only symbols left in the global namespace tend to be from the Windows API. I avoid pulling symbols from other namespaces into the current namespace (e.g., I never have using namespace std;), preferring instead to qualify things explicitly. This is in line with Google's C++ style guide.

I've therefore gotten into the habit of qualifying WinAPI function calls with :: for a few reasons:

  1. Consistency. For everything outside the current namespace, I refer to it explicitly (e.g., std::string), so why not refer to the Windows APIs explicitly (e.g., ::LoadLibraryW)? The Windows APIs namespace is the global namespace.

  2. A lot of the WinAPI functions are named generically (e.g., DeleteObject). Unless you're very familiar with the code you're reading, you may not know whether DeleteObject is a call to something in the current namespace or to the Windows API. Thus, I find the :: clarifies.

  3. A lot of Windows frameworks have methods with the same names as the raw calls. For example, ATL::CWindow has a GetClientRect method with a slightly different signature than WinAPI's GetClientRect. In this framework, it's common for your class to be derived from ATL::CWindow, so, in your class's implementation, it's normal to say GetClientRect to invoke the inherited ATL method and ::GetClientRect if you need to call the WinAPI function. It's not strictly necessary, since the compiler will find the right one based on the signature. Nevertheless, I find that the distinction clarifies for the reader.

(I know the question wasn't really about WinAPI, but the example was in terms of WinAPI.)

余生再见 2024-12-15 07:55:10

不,如果您的类中没有 LoadLibrary 方法,您就不需要使用全局作用域。事实上,您不应该使用全局作用域,因为如果您稍后将LoadLibrary添加到您的类中,您的意图可能是覆盖全局函数...

No, if you do not have a LoadLibrary method in your class you do not need to use the global scope. In fact, you should not use global scope because if you later on add a LoadLibrary to your class your intentions is probably to override the global function...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文