C ++中“ using”声明的范围是什么?


100

我在C ++中使用'using'声明将std :: string和std :: vector添加到本地名称空间(以节省键入不必要的'std ::'s)。

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

class Foo { /*...*/ };

该声明的范围是什么?如果我在标头中执行此操作,是否会将这些“使用”声明注入每个包含标头的cpp文件中?


18
以防万一,这里的其他答案不清楚:- 不要在包含文件/头文件的文件作用域中放置using声明(或using指令)!这将使标题用户感到头疼。
Michael Burr

其实,不要把一个using声明(更不用说指令)的头在所有即使是在一个命名空间!有关此问题的信息,请参见在命名空间中使用声明的范围
尼尔斯·冯·巴特

@NilsvonBarth:有点简化了。使用using类和功能范围有关讨论的问题是安全。
塞巴斯蒂安·马赫


您可能有兴趣阅读有关ADL C ++查找 功能的信息
亚历克西斯威尔克

Answers:


59

在C ++中#include头文件时,它将头文件的全部内容放到将其包括在源文件中的位置。因此,包含具有using声明的文件具有与将using声明放置在每个包含该头文件的文件顶部的效果完全相同的效果。


51
...这通常是一件坏事。
Catskul

17
但是,如果将using声明放在a namespace之内,则该声明仅限于该名称空间的范围,通常就可以了(对您的特定需求和样式有通常的警告)。
2012年

1
...但是如果您确实要在命名空间中使用,请确保不要这样做,以避开通常是个坏主意的事情,例如您不能将在命名空间Y外部声明的类方法包含在另一个命名空间之内名称空间X,这样您就可以在本地使用名称空间X。这就是为什么我们首先使用名称空间::解析器的原因。如果这是键入问题的重中之重,要么是宏(很容易导致代码味道),要么更好,请将其隔离到自己的源.cpp中,您将仅在其中使用名称空间。
osirisgothra 2014年

1
尽管此答案和类似答案是不错的建议,但它们并不能回答问题。
Emile Cormier

116

头文件没有什么特别的,可以使using声明不出现。在编译甚至开始之前,这是一个简单的文本替换。

您可以将using声明限制为作用域:

void myFunction()
{
   using namespace std; // only applies to the function's scope
   vector<int> myVector;
}

12
我从没想过我可以在函数中使用它!
Agostino'3

1
我有一堆名称空间都由一个“ conglomerator”类型的文件使用,而gmock单元测试非常繁琐,因为每个测试都使用特定命名空间中的东西,因此我认为必须限定每个变量。用using一个函数内部(甚至是GTEST TEST宏!)让我的生活变得更美好!
dwanderson

54

using语句的范围取决于它在代码中的位置:

  • 放置在文件的顶部,在整个文件中具有作用域。
  • 如果这是一个头文件,它将在所有包含该头文件的文件中具有作用域。通常,这不是“ 一个好主意 ”,因为它可能会产生意想不到的副作用
  • 否则,using语句在包含该语句的块中一直存在,范围从它发生到块的末尾。如果将其放置在方法内,它将在该方法内具有作用域。如果将其放在类定义中,它将在该类中具有作用域。

5
我认为不可能using在类范围内添加语句...?我有与OP相同的问题,因为我想避免std::在整个地方都键入文字。我得到的类使用了很多带有智能指针的向量,并且五个字符的std::前缀增加了很多行长-我发现读起来更糟。所以我想知道using包含类的名称空间中的指令是否可以?(即使在标头中也是如此。)
thomthom 2013年

5
如果将它放在a的范围内namespace { ... }怎么办?
einpoklum 2015年

因此,您可以完全编写:{使用名称空间blabla; class blah {}; }且该用法仅适用于该类?
Dinaiz'9

8

作用域是using声明所在的作用域。

如果这是全局范围,那么它将在全局范围内。如果它在头文件的全局范围内,则它将在每个包含头文件的源文件的全局范围内。

因此,一般建议是避免在头文件的全局范围内使用声明


3
那还不够强大。与待办事项更换忌不
马丁纽约

1
避免比没有强。“避免撞到其他汽车”
bobobobo

6

在引用的情况下,该文件(“翻译单位”)意味着所有包含该文件的文件。

您也可以将using语句放入类中,在这种情况下,它仅对该类有效。

通常,如果您需要在标头中指定名称空间,通常最好仅对每个必需的标识符进行完全限定。


请注意,using类中的声明的行为方式与类外部的行为不同-例如,您不能使用它来cout代替std::cout类的作用域。
2012年

2

那是正确的。范围是使用using声明的模块。如果模块包含的任何头文件都具有using声明,则这些声明的范围将是该模块以及包含相同头的任何其他模块。


1

当他们说“不要”时,有些评论是相当不合格的。那太严厉了,但是您必须了解何时可以。

写作using std::string永远都不行。using ImplementationDetail::Foo如果在标头中声明ImplementationDetail :: Foo时可以编写自己的标头,那么,如果using声明发生在名称空间中,则可以。例如

namespace MyNS {
    namespace ImplementationDetail {
        int Foo;
    }
    using ImplementationDetail::Foo;
}

1
标头的用户然后可以写MyNS::Foo
Peter Remmers

一个更好的例子是using boost::posix_time::ptime。当然,用户可以写东西,MyNS::ptime但这还不是世界末日,并且可以被拥有这样的功能的便利所抵消MyFunction(ptime a, ptime b)
2012年

5
为什么using std::string从来好吗?甚至在您自己的命名空间中保存很多std::前缀?
thomthom 2013年

@thomthom包裹在诸如您自己的名称空间之类的范围中就可以。
jcoffland
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.