“使用命名空间”的目的是什么?

What's the purpose of: "using namespace"?

提问人:fredoverflow 提问时间:12/6/2010 最后编辑:Jan Schultkefredoverflow 更新时间:9/21/2023 访问量:6798

问:

有令人信服的论据反对,那么为什么它被引入语言中呢?不会破坏命名空间的目的吗?我为什么要写?有没有我不知道的问题,也许是在成语的行中,或者类似的东西,优雅地解决了?using namespace stdusing namespaceusing namespaceusing namespaceusing std::swap

C++ 命名空间 language-design using-directives

评论

12赞 12/6/2010
少打字是一个非常诱人的论点......
0赞 kenny 12/6/2010
使用“使用”的概念是绕过命名空间或反对命名空间,但它在您需要时就在那里。
3赞 James McNellis 12/6/2010
另请参阅 Herb Sutter 的“迁移到命名空间”。
0赞 fredoverflow 12/6/2010
@James:我有点不同意那篇文章:)由于在语言中引入了命名空间,现有代码从未中断,因为头文件的命名约定同时发生了变化。因此,如果您的遗留代码确实如此,那么在没有资格的情况下可以很好地工作。所以迁移代码对我来说绝对不是一个论点。#include <iostream.h>cincoutstd::
0赞 James McNellis 12/6/2010
@Fred:所以,忽略短期解决方案。“避免完全使用指令,尤其是在头文件中”和“永远不要在头文件中使用声明编写命名空间”的正确长期解决方案是极好的建议。

答:

21赞 UncleBens 12/6/2010 #1

首先,这是在命名空间中使用运算符重载的方法(例如using namespace std::rel_ops;using namespace boost::assign;)

简洁也是一个强有力的论据。你真的喜欢打字和阅读吗?此外,当您以函数式风格编写代码时,您将在 和 命名空间中使用无数对象。std::placeholders::_1_1stdboost

另一个重要的用法(尽管通常不会导入整个命名空间)是启用与参数相关的查找:

template <class T>
void smart_swap(T& a, T& b)
{
    using std::swap;
    swap(a, b);
}

如果 swap 在与 T 相同的命名空间中为某种类型的 T 重载,这将使用该重载。如果显式调用,则不会考虑该重载。对于其他类型的类型,这回退到 。std::swapstd::swap

顺便说一句,using 声明/指令不会破坏命名空间的目的,因为在出现歧义的情况下,您始终可以完全限定名称。

评论

2赞 Martin York 12/6/2010
就我个人而言,我对“使用 <X>”很好,这是我遇到问题的“使用命名空间 <X>”(除了rel_ops等少数例外)。
2赞 Diego Sevilla 12/6/2010 #2

大多数时候,它只是编写代码的快捷方式。您可以将名称导入到封闭的上下文中。我通常将它限制为文件,因为当您将 using 指令包含在文件中时,它会污染包含它的所有文件。另一个好的做法是将环境限制在尽可能封闭的环境中,例如,在方法主体声明内部。我认为它是一种方便,仅此而已,类似于命名空间别名,例如:.cpp.husing namespace

namespace po = boost::program_options;

然后你可以写

po::variables_map ...
1赞 Kate Gregory 12/6/2010 #3

人们特别反对,但不反对;或者引用(如果你明白我的意思,那就是使用命名空间,只是不是它。此外,大多数反对意见都在头文件中。在可以立即看到效果的源文件中,它的危害较小。using namespace std;using namespace BigCorpstd::coutusingusing namespace std

命名空间是一个非常有用的概念,它允许我拥有一个名为 Date 的类,即使我使用的库有一个名为 Date 的类。在将它们添加到语言中之前,我们必须有类似 和 的东西(我的公司 Gregory Consulting 早于)。使用命名空间(带或不带关键字)可以让我们编写更干净、更整洁的代码。但是当你每次都不得不说时,你就失去了更干净、更整洁的部分。 [免责声明:我实际上不再使用我自己的字符串类了 - 想象一下一些适当的名称冲突。这就是这句话的魅力所在。不要将它放在标头之外,不要将其应用于 ,您通常应该避免麻烦。GCDateGCStringstd::stringusingGregcons::stringusingstd

评论

1赞 celtschk 7/15/2013
我会说,不要使用 ,但是 ;这既适用于标准名称,也适用于其他名称。例如,如果不在标头中完成,则没有错。using namespace foousing foo::whateverusing std::cout
0赞 CadentOrange 12/6/2010 #4

我发现它在使用具有深度嵌套命名空间的库时很有用。Boost 库就是这样一个例子。到处都是成像打字......boost::numeric::ublas::matrix<double> m

要避免的事情是在头文件中执行,因为这有可能严重搞砸包含所述标头的任何程序。始终将语句放在 .cpp/.cxx 文件中,以便将其限制为文件范围。using namespaceusing namespace

评论

2赞 jalf 12/6/2010
但是命名空间别名也可以解决这个问题。或者,您可以有选择地仅导入。matrix
2赞 CadentOrange 12/6/2010
或者你可以使用 typedef,例如 并在代码的其余部分使用。这就是C++的美妙/诅咒:有几种方法可以解决同一个问题。typedef boost::numeric::ublas::matrix<double> DoubleMatrixDoubleMatrix
-1赞 pwnedu46 12/6/2010 #5

“命名空间允许将类、对象和函数等实体分组到一个名称下。这样,全局范围可以划分为“子范围”,每个子范围都有自己的名称。其中 identifier 是任何有效的标识符,entities 是命名空间中包含的类、对象和函数的集合”

更多信息请见:http://www.cplusplus.com/doc/tutorial/namespaces/

1赞 celtschk 7/15/2013 #6

引入的主要原因是向后兼容性:如果您有很多使用大量(标准版本的)标准库函数和类的预命名空间代码,则需要一种简单的方法来使该代码与符合标准的编译器一起使用。using namespace

顺便说一句,至少对于 C++98 而言,参数相关的查找规则意味着它不会在模板中执行您想要的操作(我不知道这在标准的更高版本中是否发生了变化)。using namespace std::rel_ops

例:

template<typename T> bool bar(T t)
{
  return t > T();
}

namespace foo
{
  class X {};
  bool operator<(X, X);
}

using namespace std::rel_ops;

int main()
{
  X x;
  bar(x); // won't work: X does not have operator>
}

请注意,放入也无济于事。using namespacenamespace foo

但是,在正确的位置使用声明会有所帮助:

template<typename T> bool bar(T t)
{
  return t > T();
}

namespace foo
{
  class X {};
  bool operator<(X, X);
  using std::rel_ops::operator>;
}

int main()
{
  X x;
  bar(x); // now works: operator> found per ADL via the using declaration in `namespace foo`
}