下面是示例代码
#include <iostream>
using namespace std;
namespace A {
void f() { cout << "a" << endl; }
}
namespace B {
void f() { cout << "b" << endl; }
}
namespace C {
using namespace A;
using namespace B;
using A::f;
}
namespace D {
using A::f;
using namespace A;
using namespace B;
}
int main()
{
C::f();
D::f();
}
当我在Visual Studio 2015中尝试时,这会打印“a”两次,这种行为是由标准定义还是特定于此实现?
它由标准定义(这样的事情总是如此)。要意识到的关键是,你的各种using namespace
线对你的程序没有任何影响。
using namespace Foo
是一个“using指令”,它影响名称查找,该查找由作用域内的代码执行。也就是说,如果你的namespace C {}
块中的一些后来的函数试图找到一个名为foo
的对象,那么A
和B
将成为编译器搜索找到foo
的地方之一。相反,如果后面的代码引用C::foo
,它将不会改变编译器的外观。单个块中两个连续using namespace
s的顺序并不重要,因为每个块都具有完全效果,直到块结束。
你能在f
或C
找到D
的原因是“使用声明”using A::f
。与using-directive不同,using声明具有将名称注入作用域的效果,这样其他代码可以将名称称为在该作用域内。
来自cppreference.com的以下两段应该解释这种行为:
using-directive [
using namespace A;
]不会在其出现的声明区域中添加任何名称(与using-declaration [using A::f;
]不同),因此不会阻止声明相同的名称。出于非限定查找的目的,using-directives是可传递的:如果一个scope包含一个指定namespace-name的using-directive,它本身包含某些namespace-name-2的using-directive,那么效果就好像using指令来自第二个命名空间出现在第一个。这些传递命名空间发生的顺序不会影响名称查找。
简单地说:using A::f;
就像你在这个命名空间中声明了这个函数一样。 using namespace A;
只会导致typename查找行为,就像你的情况下当前命名空间(C
或D
)是A
中的命名空间一样。
这与如何相似
namespace A {
void f() { cout << "a" << endl; }
namespace B {
void f() { cout << "b" << endl; }
}
}
和
namespace A {
namespace B {
void f() { cout << "b" << endl; }
}
void f() { cout << "a" << endl; }
}
是等价的。