参考:http://en.cppreference.com/w/cpp/language/namespace#Using-directives
1 #include2 3 namespace A{ 4 struct S{ 5 S(){ 6 printf("A::S(int) called \n"); 7 } 8 }; 9 }10 11 namespace B{12 struct S{13 S(){14 printf("B::S(int) called \n");15 }16 };17 using namespace A;18 S s;19 }20 21 int main()22 {23 using namespace B;24 S s;25 }
第23行讲述了using-directive(以下简称U.D.)的第一个效应:把B名字空间虚拟的引入22行和25行包裹的块(block)。当第24行,遇到S这个符号时,B::S也是候选者,所以,程序员节省了几个打字(B::S).
但是编译失败,因为17行,在B块中,引入了A名字空间。因此,第24行名字解析时,会遇到两个候选者:A::S 和 B::S。
第18行讲述了U.D.的第二个效应,当本块的名字和其它名字冲突时,编译器不报错,会选择本块的名字(就是第12行定义的S)。按此思路,可以修改上述编译失败的代码为:
#includenamespace A{ struct S{ S(){ printf("A::S(int) called \n"); } };}namespace B{ struct S{ S(){ printf("B::S(int) called \n"); } }; using namespace A; S s;}int main(){ struct S{ S(){ printf("main::S(int) called \n"); } }; using namespace B; S s;}
这意味着什么?一个unqualified name(例如:S s; 而不是A::S s;)会随着工程的庞大,有时会编译失败,有时会改变含义。难以管理,这是很多编程规范中,不建议using namespace std;放到头文件的原因。
局部使用只影响局部,所以不能一概否定U.D. 例如:
1 #include2 3 namespace A{ 4 struct S{ 5 S(){ 6 printf("A::S(int) called \n"); 7 } 8 }; 9 }10 11 namespace B{12 struct S{13 S(){14 printf("B::S(int) called \n");15 }16 };17 }18 19 int main()20 {21 {22 using namespace B;23 S s;24 }25 26 {27 using namespace A;28 S s;29 }30 }
第23行和第28行,只收到本块的U.D的影响。所以局部简单代码应允许使用U.D.以简化代码:
1 { 2 std::cout << std::hex << 100 << std::endl; 3 } 4 5 { 6 using namespace std; 7 cout << hex << 100 << endl; 8 } 9 10 {11 using std::cout;12 using std::hex;13 using std::endl;14 cout << hex << 100 << endl;15 }
哪一个您更喜欢呢?显然在这个场合,没人用using-declare吧?
using namespace xxx;在名字查找时,提供一个类似额外搜索路径的机制。当主路径没有找到名字时,才考虑这个额外搜索路径。例如:
1 #include2 3 namespace Outer{ 4 5 int i=100; 6 7 } 8 9 int main(){10 11 int i=20;12 {13 using namespace Outer;14 i=0;15 }16 17 std::cout << "Outer::i=" << Outer::i;18 }
第14行,因为在主搜索路径上i可以找到,就是第11行的int i=20; 因此i没有歧义。主搜索路径,就是一些嵌套的大括号构成的包裹关系路径。
1 #include2 3 namespace Outer{ 4 int i=100; 5 } 6 7 namespace KK{ 8 int i=200; 9 }10 11 namespace {12 int i=300;13 }14 15 int main(){16 using namespace KK;17 {18 using namespace Outer;19 i=0;20 }21 }
第19行的i;我们在主搜索路径上人脑搜索一下,就是17~20行为第一层,15~21行为第二层,都找不到i的定义。这时候using namespace引入的辅助搜索路径被考了。会发现有三个名字空间的i;
匿名名字空间的i, KK::i, Outer::i 。编译器会报错,抱怨候选者太多,请程序员明确指示用哪一个。如果using namespace被放到头文件里,还需要人脑做#include展开,所以带给程序员的负担是比较大的。所以,应严格控制using namespace的作用范围。
总结:建议在最内层的块内使用using namespace,就是第18行的样子。谨慎在外层块(第16行)使用,禁止在文件的作用域(包括头文件)使用using namespace