在C ++中使用`using`还是避免使用?


17

由于ADL造成了语义上的细微差别,我通常应如何使用using?为什么?是否与情况有关(例如,标头为#included而源文件为d)?

另外,我该选择::std::还是std::

  1. 命名空间级别using namespace

    using namespace std;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
    
  2. 完全明确:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        return std::make_pair(s.begin(), s.end());
    }
    
  3. 命名空间级别的使用声明:

    using std::pair;
    using std::string;
    
    pair<string::const_iterator, string::const_iterator>
    f(const string &s) {
        return make_pair(s.begin(), s.end());
    }
    
  4. 局部函数使用声明:

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using std::make_pair;
        return make_pair(s.begin(), s.end());
    }
  5. 局部函数using namespace

    std::pair<std::string::const_iterator, std::string::const_iterator>
    f(const std::string &s) {
        using namespace std;
        return make_pair(s.begin(), s.end());
    }
  6. 还有别的吗

这是在C ++ 14之前的版本中进行的,因此没有使用进行归还类型推断auto



@AProgrammer:啊,谢谢您的链接,它回答了我的部分问题。:)仍在想::std::std::
user541686 2012年

4
我正在使用std没有秒。定义std命名空间的人正在自找麻烦(并且可能正在寻找利用大多数人正在使用std而没有使用的优势)的麻烦::std
AProgrammer 2012年

Answers:


25

避免使用usingin标头,因为这会破坏名称空间的用途。

可以在源文件中使用它,但是在某些情况下(例如using std),我还是会避免使用它。

但是,如果您嵌套了名称空间,则可以:

namespace A {
namespace B {
namespace C {
class s;
} // C
} // B
namespace D{
using B::C::s;
} // D
} // A

6
+1令人惊讶的是,有多少教程和大学课程仅告诉您使用using关键字,而没有详细说明为什么使用名称空间开头。
杰弗里·斯威尼

人们希望继续使用iostream,字符串等。他们不需要键入std ::每次都想使用一个东西,或者必须记住在代码之前放置另一个样板,如果忘记这些样例,将导致无用的错误。 。:(
Colen 2012年

像typedef std :: string sstring; 可以替代吗?
Giorgio 2012年

1
@Colen:这些可怜的人可以使用using std::cout和与朋友交往,但这并不是cout已经很可怕的名字了。
本杰明·班尼尔

1
如果您在“我的第一门C ++课程”的第一天是一名大学生,那又是另一件事,它可能导致您不了解的语法错误。我们很容易弄清楚,因为我们是经验丰富的程序员,但是当您尝试学习该语言时,又需要担心不需要的另一件事。
科伦2012年

11

当在源文件中放置一个using语句时,请放入您需要的东西。例如:

using std::string;
using std::ostringstream;

这里的问题是,如果您这样做

using namespace std;

您可以将std中的所有单项拉入全局名称空间。当您在代码中不小心使用与您在std中完全不知道的名称匹配的名称时,这会导致非常有趣的错误消息。如果您只是投入所需的东西,那么您就不会有这个问题(或更准确地说,下一个使用您的代码的程序员就不会有这个问题)。


另外,您也可以using namespace在函数作用域中避免该问题。
陶Szelei

2
@fish-实际上,在函数范围内执行“使用名称空间”并不能避免该问题,它只是限制了可能出错的空间。而且,如果最终在每个函数中都添加了“使用名称空间”,则与仅在全局范围内进行操作没有太大区别。
迈克尔·科恩

虽然C ++确实允许在函数级别上声明类型,但这并不是一件常见的事。除此之外,很容易从编译器输出中发现可能的名称冲突(但您是对的,这不会阻止它们)。
陶Szelei

2

如VJovic所指示,请勿using在头文件中使用。using头文件中的“。”会以源文件可能不期望的方式影响当前的编译单元(.cpp文件)。

using namespace也应避免在源文件中使用。这会将每个符号带入与源文件相同的作用域。如果您使用命名空间中的特定符号,则对读者来说更清楚您在做什么。


2
出于实际的考虑,除非您的代码覆盖了常用名称,否则我宁愿using namespace JoystickModule在.cpp文件的开头看到内容,也不希望将其JoystickModule::附加到整个对象上。
亚历克斯P

@AlexP:那正是我的方法。using我正在处理的我自己的名称空间的一条语句,其他所有内容保持名称空间。
本杰明·克洛斯特

我应该详细说明“使用命名空间中的特定符号”。我宁愿使用显式的符号提升,而不是在每次使用时都给每个符号加上前缀(这不利于提高可读性)。using SomeNameSpace::SomeSymbol。这样可以避免将每个符号从命名空间移到当前作用域。
比尔·门

0

using用标头编写是创建各种讨厌的不可能调试的错误的最佳方法。千万不能做到这一点。

using namespace XYZ在源文件中写入会更好一些,但是仍然会引起您无数的头痛。安全的方法是明确指定您正在使用的内容,例如using Foo::Bar

假设您有带有以下内容的Bar.cpp:

//Bar.cpp
using namespace Foo;
namespace
{
    double increment(double v) { return (v + 1); }
}

void Bar::someFunction()
{
    //...
    int currentIndex = 0;
    int nextIndex = increment(currentIndex);
    //...
}

该函数运行良好,直到一天-似乎相关类中的代码均未更改-其行为已更改:突然currentIndex似乎总是相差一个。浏览最近的更改,即使与代码远程相关,也没有发现任何更改。

最终,您发现了原因:
您(间接地)包括在Foo.h某个地方。在Foo名称空间的文件中,添加了一个新功能:

//Foo.h
namespace Foo
{
    //...
    int& increment(int& v) { v += 1; return v; };
    //...
}

这无疑是increment(int)比您的函数更好的匹配increment(double)-因此现在改为Foo::increment()调用by Bar::someFunction()。哎呀

(如果您要编写using的标题using namespace Foo可能很可能在包含树中的任何位置 ...)

因此,请不要using在标头中编写任何内容,也要警惕using namespace在源文件中编写内容。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.