为什么在类/结构级别内不允许使用“namespace X;”?
class C { using namespace std; // error }; namespace N { using namespace std; // ok } int main () { using namespace std; // ok }
编辑 :想知道背后的动机。
我不知道确切的,但我的猜测是,允许在课堂上的范围可能会造成混乱:
namespace Hello { typedef int World; } class Blah { using namespace Hello; public: World DoSomething(); } //Should this be just World or Hello::World ? World Blah::DoSomething() { //Is the using namespace valid in here? }
由于没有明显的做法,标准只是说你不能。
现在,当我们谈到命名空间范围时,这个原因不那么令人困惑:
namespace Hello { typedef int World; } namespace Other { using namespace Hello; World DoSomething(); } //We are outside of any namespace, so we have to fully qualify everything. Therefore either of these are correct: //Hello was imported into Other, so everything that was in Hello is also in Other. Therefore this is okay: Other::World Other::DoSomething() { //We're outside of a namespace; obviously the using namespace doesn't apply here. //EDIT: Apparently I was wrong about that... see comments. } //The original type was Hello::World, so this is okay too. Hello::World Other::DoSomething() { //Ditto } namespace Other { //namespace Hello has been imported into Other, and we are inside Other, so therefore we never need to qualify anything from Hello. //Therefore this is unambiguiously right World DoSomething() { //We're inside the namespace, obviously the using namespace does apply here. } }
因为C ++标准明确禁止它。 来自C ++ 03§7.3.4[namespace.udir]:
使用指令 : using namespace :: opt nested-name-specifier opt namespace-name ;
using指令不应出现在类作用域中,但可能出现在名称空间作用域或块作用域中。 [注意:在using-directive中查找命名空间名时,只考虑命名空间名,参见3.4.6。 ]
为什么C ++标准禁止它? 我不知道,请求批准语言标准的ISO委员会成员。
我相信它的理由是它可能会令人困惑。 目前,在处理类级标识符时,查找将首先在类作用域中search,然后在封闭的名称空间中search。 在类级别允许using namespace
将会对如何执行查找产生相当多的副作用。 特别是在检查特定的类作用域和检查封闭的名称空间之间必须执行一段时间。 即:1)合并类级别和使用的名称空间级别查找,2)在类作用域之后但在任何其他类作用域之前查找使用的名称空间,3)在封闭名称空间之前查找使用的名称空间。 4)查找与封闭名称空间合并。
- 这会产生很大的不同,在类层次上的标识符会隐藏封闭名称空间中的任何标识符,但不会影响已用名称空间。 效果会很奇怪,因为从不同命名空间和相同命名空间的类中访问已用名称空间将会有所不同:
。
namespace A { void foo() {} struct B { struct foo {}; void f() { foo(); // value initialize a A::B::foo object (current behavior) } }; } struct C { using namespace A; struct foo {}; void f() { foo(); // call A::foo } };
- 在此课程范围之后查找。 这会影响基类成员的奇怪效果。 当前的查找不会混合类和名称空间级别的查找,而在执行类查找时,它将在考虑封闭名称空间之前一直到基类。 这种行为是令人惊讶的,因为它不会将名称空间视为与封装名称空间类似的级别。 同样, 使用的名称空间将优先于封闭的名称空间。
。
namespace A { void foo() {} } void bar() {} struct base { void foo(); void bar(); }; struct test : base { using namespace A; void f() { foo(); // A::foo() bar(); // base::bar() } };
- 在封闭名称空间之前进行查找。 这种方法的问题再一次令人惊讶。 考虑命名空间是在不同的翻译单元中定义的,以便下面的代码不能一次全部被看到:
。
namespace A { void foo( int ) { std::cout << "int"; } } void foo( double ) { std::cout << "double"; } struct test { using namespace A; void f() { foo( 5.0 ); // would print "int" if A is checked *before* the // enclosing namespace } };
- 与封闭的命名空间合并。 这与在命名空间级别应用
using
声明具有完全相同的效果。 它不会增加任何新的值,但另一方面会使编译器实现者的查找复杂化。 名称空间标识符查找现在独立于触发代码中代码的位置。 在类内部时,如果查找在类作用域中找不到标识符,则它将回退到名称空间查找,但与在函数定义中使用的名称空间查找完全相同,则不需要维护新状态。 如果在名称空间级别findusing
声明,则将使用的名称空间的内容引入到名称空间中,以查找涉及名称空间的所有查找。 如果在类级别允许using namespace
,则根据查找触发的位置,名称空间查找完全相同的名称空间会有不同的结果,这将使查找的实现更复杂,因为没有附加值。
无论如何,我的build议是不使用using namespace
声明。 它使得代码更简单,而不必考虑所有的命名空间的内容。
但为什么你需要它? 只要把这个类放在单独的文件中,并且包含你想要的名字空间,以防万一你不希望其他类到达它们。