【问题标题】:How important is consistent usage of using declarations?using 声明的一致使用有多重要?
【发布时间】:2010-09-27 18:26:08
【问题描述】:

我对 using 声明的使用所做的大部分研究,包括阅读各种样式指南的相关部分,都表明是否在 C++ 源文件中使用 using 声明,只要它们出现在所有 #includes 之后, 是留给编码人员的决定。即使是我阅读的风格指南,为了保持一致性,通常会归结为此类常见争议的一方或另一方,在这方面也相当灵活。

我的问题是,鉴于这种高度的灵活性,使用一致的风格有多重要?例如,假设作者写了类似

using std::vector;

vector<T> v;

std::cout << v[0] << std::endl;

在 std::vector 而不是 std::cout 或 std::endl 上使用的不一致应用通常被认为是可接受的,还是会被认为是无纪律的?

【问题讨论】:

    标签: c++ namespaces using-statement


    【解决方案1】:

    我认为using 的全部意义在于您在名称之间的使用不一致。在某些块中经常需要的名称可以使用 using 声明在本地声明,而其他名称则不是。我看不出有什么问题。

    将名称声明为具有命名空间范围总是更难接受。我认为,如果明确知道该名称属于特定命名空间,这样就不会将其与其他命名空间混淆,如果它使您的代码更具可读性,那么放置 using 声明不会有什么坏处。

    【讨论】:

      【解决方案2】:

      我现在是明确声明命名空间(即不使用“使用”)的强烈支持者

      大多数人的命名空间历史都是这样的(在非平凡的,>100kloc 项目中)

      纯真 -> 风格 1

      using namespace std;
      

      哎哟 -> 风格 2

      using std::string;
      using std::vector;
      

      好的,已经够了 -> 样式 3

      std::string foo = "xxx";
      

      【讨论】:

      • @pmr100:我同意历史,我认为第一阶段很可能是由于书籍材料,但由于编辑限制,显示的示例不一般使用名称空间限定符,它们都占用空间并掩盖所展示的原则。然而,这样的代码并不意味着成为更大程序的一部分......
      【解决方案3】:

      假设您在任何地方都没有说using namespace std;,我认为大多数开发人员不会关心其他人的代码中的一种或另一种方式。唯一可能困扰他们的是过度使用 std:: 限定符 --- 也就是说,如果你在函数中说“std::vector”20 次,也许是时候“使用 std::vector”了.否则,没有人应该在意。

      有时,在我自己的代码中,我会使用“std::”限定符来专门表示这是我使用该标识符的唯一地方。

      【讨论】:

        【解决方案4】:

        我尝试使用using(没有双关语)。

        为了节省打字,我喜欢做 typedefs,例如:

        typedef std::vector< int > IntVector;
        typedef std::vector< Foo > FooVector;
        

        【讨论】:

          【解决方案5】:

          这与其说是一个答案,不如说是与其他一些一直明确主张将命名空间作为名称的一部分的答案相对立的答案。有时,这是一个糟糕的主意。在某些情况下,您希望使用专门用于手头类型的名称​​如果存在,否则使用标准提供的替代名称。

          作为一个典型的例子,让我们考虑一个排序函数。如果你对一些 T 类型的对象进行排序,你最终会交换项目。如果存在,您想使用特殊的swap(T &amp;, T&amp;),否则使用template &lt;class T&gt; std::swap

          如果您尝试指定要显式使用的交换的全名,则必须指定一个或另一个 - 要么您指定一个专用版本,然后将您的排序实例化为不定义它自己的交换将失败,否则您指定std::swap,并忽略专门为您要排序的类型提供的任何交换。

          using 提供了一种摆脱这种困境的方法:

          using namespace std;
          
          template <class T>
          mysort(/* ... */ ) {
          
              // ...
          
              if (less(x[a], x[b])
                  swap(x[a], x[b]);
          
              // ...
          }
          

          现在,如果找到 T 的命名空间包含 swap(T &amp;, T&amp;),它将通过参数相关查找找到,并在上面使用。如果它不存在,则将找到(并使用)std::swap,因为 using namespace std; 也使其可见。

          顺便说一句,我认为只需稍作修改,using namespace x; 就可以变得几乎完全无害。就目前而言,它将来自该命名空间的名称引入当前范围。如果其中一个恰好与当前作用域中存在的名称相同,则会发生冲突。当然,问题是我们可能不知道命名空间包含的所有内容,因此几乎总是至少有一些潜在的冲突。

          修改将把using namespace x; 视为创建了一个围绕当前范围的范围,并将来自该命名空间的名称引入该周围范围。如果其中一个恰好与当前作用域中引入的名称相同,则不会发生冲突——就像任何其他块作用域一样,当前作用域中的名称将从周围作用域中隐藏相同的名称。

          我没有仔细考虑过这一点,所以毫无疑问会有一些极端情况需要更加小心地解决,但我认为总体思路可能会让很多事情变得更简单一些.

          【讨论】:

          • 对于这种特殊用法,您可以将 using namespace std;(或者更确切地说 using std::swap; 移动到函数中以限制其范围。 - 至于命名冲突,您仍然可以通过完全限定名称来消除歧义?为什么隐藏有冲突?
          猜你喜欢
          • 1970-01-01
          • 2013-02-22
          • 1970-01-01
          • 2021-08-02
          • 2016-07-23
          • 2012-05-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多