Why “using namespace X;” is not allowed inside class/struct level?

后端 未结 5 662
走了就别回头了
走了就别回头了 2020-11-27 15:35
class C {
  using namespace std;  // error
};
namespace N {
  using namespace std; // ok
}
int main () {
  using namespace std; // ok
}

Edi

5条回答
  •  借酒劲吻你
    2020-11-27 16:18

    I believe that the rationale is that it would probably be confusing. Currently, while processing a class level identifier, lookup will first search in the class scope and then in the enclosing namespace. Allowing the using namespace at class level would have quite some side effects on how the lookup is now performed. In particular, it would have to be performed sometime between checking that particular class scope and checking the enclosing namespace. That is: 1) merge the class level and used namespace level lookups, 2) lookup the used namespace after the class scope but before any other class scope, 3) lookup the used namespace right before the enclosing namespace. 4) lookup merged with the enclosing namespace.

    1. This would make a big difference, where an identifier at class level would shadow any identifier in the enclosing namespace, but it would not shadow a used namespace. The effect would be strange, in that access to the used namespace from a class in a different namespace and from the same namespace would differ:

    .

    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
       }
    };
    
    1. Lookup right after this class scope. This would have the strange effect of shadowing base classes' members. The current lookup does not mix class and namespace level lookups, and when performing class lookup it will go all the way to the base classes before considering the enclosing namespace. The behavior would be surprising in that it would not consider the namespace in a similar level to the enclosing namespace. Again, the used namespace would be prioritized over the enclosing namespace.

    .

    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()
       }
    };
    
    1. Lookup right before the enclosing namespace. The problem with this approach is again that it would be surprising to many. Consider that the namespace is defined in a different translation unit, so that the following code cannot be seen all at once:

    .

    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
       }
    };
    
    1. Merge with the enclosing namespace. This would have the exact same effect that applying the using declaration at the namespace level. It would not add any new value to that, but will on the other hand complicate lookup for compiler implementors. Namespace identifier lookup is now independent from where in the code the lookup is triggered. When inside a class, if lookup does not find the identifier at class scope it will fall back to namespace lookup, but that is exactly the same namespace lookup that is used in a function definition, there is no need to maintain new state. When the using declaration is found at namespace level, the contents of the used namespace are brought into that namespace for all lookups involving the namespace. If using namespace was allowed at class level, there would be different outcomes for namespace lookup of the exact same namespace depending on where the lookup was triggered from, and that would make the implementation of the lookup much more complex for no additional value.

    Anyway, my recommendation is not to employ the using namespace declaration at all. It makes code simpler to reason with without having to keep all namespaces' contents in mind.

提交回复
热议问题