My namespace importing trick imported the same three namespaces into each top-level namespace, yet it worked?


A little while ago, I noted a technique formally known as namespace composition. There was one section that appeared to confuse some people:

namespace ABI
{
  using namespace Windows::System::Profile::SystemManufacturers;
  using namespace Windows::UI::ViewManagement;
  using namespace Windows::Security::Cryptography;
}

namespace cx
{
  using namespace Windows::System::Profile::SystemManufacturers;
  using namespace Windows::UI::ViewManagement;
  using namespace Windows::Security::Cryptography;
}

namespace winrt
{
  using namespace Windows::System::Profile::SystemManufacturers;
  using namespace Windows::UI::ViewManagement;
  using namespace Windows::Security::Cryptography;
}

Was this a copy/paste error? After all, the same three namespaces are being imported each time.

Well, no, actually. The text is the same, but each one is interpreted differently.

Let's take a simpler example:

namespace X { namespace W { void f(); }}
namespace Y { namespace W { void f(); }}
namespace W { void f(); }

namespace X
{
    using namespace W;
    auto do_something = f;
}

namespace Y
{
    using namespace W;
    auto do_something = f;
}

namespace Z
{
    using namespace W;
    auto do_something = f;
}

Each of the three namespaces contain a using namespace W;, but each one refers to a different namespace, which you can see by pasting the above into Compiler Explorer and observing the definitions of X::do_something, Y::do_something, and Z::do_something.

The first using namespace W; takes place inside a namespace X, so the search begins relative to that namespace, and we find it at ::X::W.

Similarly, the second using namespace W; takes place inside a namespace Y, so the search begins relative to that namespace, and we find it at ::Y::W.

The third using namespace W; takes place inside a namespace Z, so the search begins relative to that namespace. There is no ::Z::W, so we resume our search at the next outer namespace, which is the global namespace, and we find it as ::W.

Even though the three namespace imports are textually identical, they have different effects because they each occur in different contexts.

I wrote it this way because it showed that I was "pulling in" the relative namespace declarations into the corresponding first-level namespace.

Comments (10)
  1. Gee Law says:

    It surprises me that someone with any proficiency in C++ would ask such a question. And not just someone, but three someones.

    1. Scarlet Manuka says:

      Not everyone who reads this blog is proficient in C++. I’m certainly not. Then again, I thought it was pretty clear what was going on in the referenced article. It was only necessary to look at the previous section, which had all the fully qualified namespaces listed out.

      1. GL says:

        Agreed. I would say any sane language with any scoping would perform name look-ups that way.

  2. Peter says:

    Might it be better to fully qualify the nested namespaces?

    namespace X
    {
    using namespace ::X::W;
    }

    It would avoid potential confusion. The fact that the first two namespaces are importing relative namespaces and the third is importing a top-level namespace is pretty subtle, in my opinion. There’d be no way to tell that was happening in a code review, for example, unless you were intimately familiar with the external definitions of W, X, Y, and Z.

    1. Darran Rowe says:

      I would disagree about confusion and this being subtle because if you find this subtle and it confuses you then you simply don’t understand the language. The unqualified name lookup rules are easy to understand and (not including ADL for functions) the same for variables, functions and namespaces. Basically start at the current namespace and then work outwards until you hit the global namespace.
      For the code review, that would imply that you take incomplete code to the review, i.e. not taking at least the declaration of the namespace you are importing and all of the contained items. Because remember, to be able to use the using directive in the way that Raymond mentioned, you need to be familiar with the external definitions, and the only other places this would occur in your code would be in namespaces that you wrote yourself.

      1. Someone says:

        Because I don’t know: Is there really a namespace ABI::Windows::System::Profile::SystemManufacturers as also cx::Windows::System::Profile::SystemManufacturers as also winrt::Windows::System::Profile::SystemManufacturers? And when: Why on earth (assuming they contain the same)?

        1. ABI contains the raw definitions. cx contains the definitions for use in C++/CX. And winrt contains the definitinos for use in C++/winrt.

  3. Zachary says:

    It would be much better.

  4. Dave says:

    It’s easy to see why there’s no IOC++CC, the language is self-obfuscating.

  5. JohnR says:

    Really, that confused people? I guess some people need to brush up on their C++.

Comments are closed.

Skip to main content