何时在C ++中使用“::”作为全局范围?

时间:2013-06-25 05:38:02

标签: c++ namespaces scope

每隔一段时间,我偶然发现一些代码,我正在考虑我的代码风格。今天是其中一天......

我知道您为什么要使用范围运算符来定义全局范围。事实上,scope resolution operator without a scope这是一个很好的链接告诉你原因。

但是,我看到了一些让我今天想到的东西。所有有问题的类都包含在项目的命名空间中(好!),但我确实看到了全局范围运算符的大量使用。也就是说,它被用于C库中的所有东西(除了uint8_t等之外......是的,程序员使用了这个库的.h版本,因为他们运行的g ++版本显然仍然对新的C ++发出警告标准)。这有用吗?我认为这就像浪费字符一样(让我想起使用这个指针......除了复制构造函数和赋值运算符的情况,它有助于澄清哪个对象是哪个)。我错过了什么吗?当然,有人可以来找我们沿着usleep()或stderr(我看到“::”的最多用法)的名字,但他们不知道这样做可能会破坏一些可怕的东西吗?你在什么时候用范围操作符说“搞砸”,只是告诉自己,在命名空间中以某种方式命名函数的人会遇到麻烦?

所以我的问题是......在这种情况下使用全局范围运算符的“正确”(主观我理解)方式是什么?如果未包含在std或您自己的命名空间中的所有内容都明确定义了全局范围吗?我倾向于小心谨慎并使用“std ::”来避免使用指令,但是在这里使用全局范围运算符可以获得什么?我倾向于认为为了清楚起见它确实导致我们没有从当前命名空间获得有问题的变量或函数这一事实,但我在包含它而不是今天的开发之间徘徊。

与往常一样,感谢您的帮助和指导,因为我希望我的代码更清晰,更易读,并且(当然)更加出色。

4 个答案:

答案 0 :(得分:10)

我很少使用它;只有当一些歧义需要因任何原因解决时。不过,这是非常主观的。

在某些情况下(例如,在模板内部),您担心ADL仅在某些情况下会导致含糊不清:

template <typename T>
void foo(T t)
{
   ::bar(t);  // :: just in case there's a `bar` in `T`'s namespace
}

答案 1 :(得分:2)

几乎没有正确答案,因为它几乎完全与风格相关,但有一个例外,如果您认为您可能希望更改您要导入的某些声明/定义,其中case,当你使用它们时,你没有指定任何范围并使用using指令(从命名空间导入子集)或using namespace指令导入它们以从命名空间导入整个集合

大多数情况下,using指令用作便捷指令,但它是指导使用哪些声明/定义的强大方法。我的偏好是不指定范围并导入声明。这样做可以在需要时轻松更改,同时降低视觉噪音。此外,指定范围意味着我将“锁定”在我获取声明的位置(好吧,我必须进行全局搜索并替换以更改它)。

如果存在冲突(您尝试使用从多个命名空间导入的具有相同名称的声明项目),编译器会通知您,因此没有真正的危险。

答案 2 :(得分:1)

可读代码具有最少的噪音。名称空间前缀通常只提供噪音。所以基线就是没有它们。

命名空间被引入C ++主要是为了处理第三方的东西。要允许库删除前缀,而客户端可以通过使用来使用简洁的名称。

仅仅因为 在许多名称空间中具有相同的名称并不意味着它也是一个好主意。如果项目使用某些环境,平台API,库集,无论将名称放在全局中,那么这些名称最好避免用于其他目的。无论有没有前缀,他们都会承受精神上的开销。

使用::在形状良好的代码中很少见,并且 wrapper 类中出现频繁使用的相同功能。

答案 3 :(得分:1)

考虑以下情况。

公共图书馆。

您正在编写一个带有公共标题的可导出库。而且你绝对不知道你的标题将被包含在什么环境中。例如,有人可能会这样做:

namespace std = my_space::std;
#include "your_header"

如果您只是使用:std::list<int>等,那么您的所有定义都将被破坏。因此,将::添加到全局范围内是一种很好的做法。这样你就可以完全确定你正在使用的是什么。当然,你可以using(在C ++ 11中)或typedef - 但这是一种错误的方式进入标题。


协作.cc / .cpp文件。

在您自己的代码中,不以任何方式公开,但仍然可以由您编辑 - 这是一个很好的做法,宣布您将从命名空间外部使用 >。比如说,您的项目允许使用多个向量 - 不仅仅是std::vector。然后,在适当的地方,你放一个using指令:

// some includes

using vector = ::std::vector<int>;  // C++11
typedef ::std::vector<int> vector;  // C++03

namespace my_namespace {
...
}  // namespace my_namespace

可以在所有包含之后或在特定功能内部放置。它不仅可以控制代码,还可以使其可读并缩短表达式。

另一种常见情况 - 是全局C函数和C ++代码的混合。使用函数名称执行任何typedef都不是一个好主意。在这种情况下,您应该使用全局范围解析运算符::预先添加C函数 - 以避免编译问题,当有人在同一名称空间中实现具有相同签名的函数时。

不要将:: 用于相对类型和命名空间 - 否则您将失去使用命名空间的好处。


您自己的代码。

做你想做的和你想要的。只有一种好方法 - 您熟悉自己的代码的方式。真的,在这种情况下不要理解全局范围解决方案,如果不需要解决模糊性问题。