16

每隔一段时间,我就会偶然发现一些我正在维护的代码,这些代码挑战了我对代码风格的看法。今天是那种日子之一...

我知道为什么要使用范围运算符来定义全局范围。事实上,这里没有作用域的作用域解析运算符是一个很好的链接,告诉你为什么。

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

所以我的问题是......在这种情况下使用全局范围运算符的“正确”(我理解的主观)方式是什么?std 或您自己的名称空间中未包含的所有内容都应该明确定义全局范围吗?我倾向于谨慎行事并使用“std::”来避免使用指令,但是在这里使用全局范围运算符有什么好处吗?为了清楚起见,我倾向于认为它确实提供了这样一个事实,即我们没有从当前命名空间中获取有问题的变量或函数,但我在包括它和没有给出今天的发展之间左右为难。

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

4

4 回答 4

11

我很少使用它;仅当出于某种原因需要解决某些歧义时。不过,这是相当主观的。

在某些情况下(例如,在模板内),您可能会担心 ADL 仅在某些情况下会导致歧义:

template <typename T>
void foo(T t)
{
   ::bar(t);  // :: just in case there's a `bar` in `T`'s namespace
}
于 2013-06-25T06:10:04.640 回答
3

几乎没有正确的答案,因为它几乎完全与样式相关,除了如果您认为您可能想要从要导入某些声明/定义的位置更改,在这种情况下,当您使用它们,您不指定任何范围并使用using指令(从命名空间导入子集)或从命名空间using namespace导入整个集合的指令导入它们。

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

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

于 2013-06-25T06:04:09.233 回答
1

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

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

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

:: 在格式良好的代码中很少使用,并且在相同功能的包装类中经常使用。

于 2013-06-25T08:35:29.823 回答
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用函数名做任何 s 不是一个好主意。在这种情况下,您应该在 C 函数前面加上全局范围解析运算符::- 以避免编译问题,当有人在同一命名空间中实现具有相同签名的函数时。

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


你自己的代码。

做你想做的和你想做的。只有一种好方法 - 让您对自己的代码感到满意的方式。真的,在这种情况下,如果不需要解决歧义,请不要担心全局范围解析。

于 2013-11-17T15:03:48.520 回答