Answers:
当我阅读Google标准时,您无法在using namespace foo;
任何地方使用该指令。该指令引入了在命名空间中声明的所有内容,并且是冲突和意外行为的常见原因。其他人引用了一个非常常见的方法:您在某个地方有自己的max或min方法,并且它碰撞到src文件中,其中有人在您的方法中包含标头,然后说using namespace std;
在某些地方,允许使用using声明,其形式为 using ::foo::bar;
人们喜欢在代码中使用指令,因为它可以节省大量的键入操作,但存在风险。如果您的文件中包含很多cout语句,我可以理解,不想键入std :: cout一百次,但是您可以简单地说::: std :: cout。我将它们视为变量声明:将它们放在需要的地方。如果文件10中的一个函数需要写输出,则不要在顶部声明cout方式,而应将其放在执行实际输出的那个函数中。
#include <ostream>
//using namespace std; // NO!
//using ::std::cout; // less bad than using namespace, but I prefer to scope it
int main(int argc, char** argv)
{
int rc = do_some_stuff(argc, argv);
using ::std::endl;
if (rc) { // print the success report
using ::std::cout;
cout << "The test run completed. The return code was " << rc << '.' << endl;
} else {
using ::std::cerr;
cerr << "Unable to complete the test run." << endl;
}
return 0 == rc;
}
只有几行输出,这有点极端,但是您明白了。
可以做的另一件事是别名或typedef以最大程度地减少键入。我没有发现std :::那样糟糕,但是我们拥有大量的源代码,其中包含数十个模块,有时我们必须编写类似的代码console_gui::command_window::append("text")
。一段时间后,这变得很乏味,并导致很多行。我全都喜欢
typedef console_gui::command_window cw;
cw::append("text");
只要别名是在本地范围内完成的,并且保留足够的上下文以使代码可读即可。
std::endl
在stdout
/ 上进行显式刷新stderr
通常是多余的,无论如何,这些流都绑定到stdout
/ stderr
。它甚至使速度变慢。
这是因为:1)它破坏了名称空间的全部目的,即减少名称冲突。2)它使使用using指令指定的整个名称空间可用于全局名称空间。
例如,如果您包含并定义了自己的max()函数,它将与std :: max()冲突。
http://en.cppreference.com/w/cpp/algorithm/max
首选项是使用std :: member_you_wish_to_use,因为它明确指出要使用的命名空间。
std::max()
名称空间前缀。还是我弄错了?
using
指令,因为在这种情况下,如果您定义了一个指令并包含<algorithm>,它将破坏max()函数。这是一个简单的案例,但是您永远都不知道可能会破坏什么。您需要了解整个库,以确保您没有破坏它,但是您不知道您的代码将来是否会破坏(即名称冲突)。
引用您提供的链接:
您可以在.cc文件中的任何位置以及.h文件中的函数,方法或类中使用using-声明。
//在.cc文件中可以。
//必须位于.h文件中的函数,方法或类中。
使用:: foo :: bar;
Google样式禁止您在全局环境中使用导入名称空间,但允许在本地环境中使用。
在任何地方使用声明只会影响代码的有限且清晰可见的部分,这是完全可以接受的。
当您污染全局上下文时,不相关的代码会受到影响(使用标头的隐含行为)。在本地情况下,什么也不会发生。
尽管这个问题已经有了有用的答案,但其中一个细节似乎太短了。
大多数程序员起初对using
关键字和namespace
用法的描述有些困惑,即使他们试图通过查找引用来学习它,因为声明和指令读起来有些等效,它们都是以d开头的相对抽象的长词。
可以通过显式命名名称空间来访问名称空间中的标识符:
myNamespace::myIdent
这可能要键入很多键。但是,如果大多数标识符以相同的方式作为前缀,这也可能降低代码的重要性。该using
关键字有助于防止这些命名空间缺点。由于using
是在编译器级别上工作的(它不是宏),因此其效果会持续到所使用的整个范围。这就是Google样式将其用法限制在定义明确的范围内的原因,例如,头文件中的类或cpp文件中的函数。
...当然使用声明是有区别的
using myNamespace::myIdent; // make myIdent an alias of myNamespace::myIdent
和使用指令
using myNamespace; // make all identifiers of myNamespace directly accessible
如果在巨大的范围使用,后者导致很多更多的混乱。
干得好:
#include <iostream>
int main()
{
std::endl(std::operator<<(std::cout, "Hello world!"));
}
通过这样编写,我们避免了使用指令和声明时容易出错的ADL。
这是一个讽刺的答案。:-D
我与Herb Sutter在Google上合作。根据C ++编码标准:
您可以并且应该在#include指令之后在实现文件中自由地使用声明和指令使用名称空间,并对此感到满意。尽管反复声明相反,使用声明和指令的名称空间并不是邪恶的,它们不会破坏名称空间的目的。相反,它们是使命名空间可用的原因。
您可以通过谨慎地避免使用using
指令并使用声明显式指定您使用的每件事(直到运算符),来解决潜在的命名空间冲突,这些冲突可能永远不会出现,并且在这种天文学上罕见的事件中可能很难解决using
,或者只是继续并开始using namespace std
。我从生产率的角度推荐后者。
大多数C ++教科书都通过使用命名空间std来教初学者。他们在传播不良的编码习惯吗?
如果您问我,情况恰恰相反,我相信上面的萨特也同意。
现在,在我的职业生涯中,由于using
跨数千万个LOC的代码库中的指令的直接结果,我总共遇到了大约3个命名空间冲突。但是,在所有这三种情况下,它们都位于跨越50,000行旧代码的源文件中,这些代码最初是用C编写的,然后混成C ++,执行了大量折衷的不同功能列表,包括来自十几个不同库的头文件,并且#includes
跨越页面的史诗清单。尽管存在史诗般的混乱,但它们并不是很难修复,因为它们在OSX(导致代码无法构建的一个OS)上导致了构建错误,而不是运行时错误。不要以这种噩梦般的方式组织代码,您应该会很好。
就是说,避免在头文件中使用 using
指令和声明。那简直是弱智。但是对于源文件,尤其是那些没有一个包含#include
指令的整个页面的源文件,我想说的是,如果您不为Google工作,请不要费力。