Search code examples
c++usingusing-directivesusing-declaration

namespace composition and selection


After reading The C++ Programming Language 4th edition (section 14.4.4 - Composition and Selection) I thought that the following program would compile correctly:

#include <iostream>

namespace foo {
    int var = 0;
    // more declarations
}

namespace bar {
    int var = 1;
    // more declarations
}

namespace baz {
    // composition of namespaces foo and bar
    using namespace foo;
    using namespace bar;
    // I thought that the following line would resolve the name clash
    using foo::var;   
}

using namespace baz;

void qux(int n) {
    if (n == var) {
        std::cout << "baz: var " << std::endl;
    } else {
        std::cout << "baz: " << n << std::endl;
    }
}

int main() {
    qux(0);
    qux(1);
}

The expected output should be

baz: var

baz: 1

When I try to compile the code above I get an error saying that the reference to 'var' is ambiguous. Using foo::var eliminates the compilation error but I would like to better understand this problem.

What is wrong in my code?

How can I resolve the name clash in a way that the namespace baz contains foo::var?

Thanks!

EDIT

As suggested in the answers below, moving the definition of qux inside the namespace baz makes it valid. Therefore, the following code compiles as expected

#include <iostream>

namespace foo {
    int end = 0;
}

namespace bar {
    int end = 1;
}

namespace baz {
    using namespace foo;
    using namespace bar;
    using foo::end;
    void qux(int n) {
        if (n == end) {
            std::cout << "baz: end " << std::endl;
        } else {
            std::cout << "baz: " << n << std::endl;
        }
    }
}

int main() {
    baz::qux(baz::end);
    baz::qux(1);
}

There is still one thing which is not completely clear to me. I thought that adding using namespace baz would make everything in baz available also in the current scope without using baz::. In other words, I would have expected that since "everything works in the namespace baz" this would be true also in the current scope after adding using namespace baz.


Solution

  • // I thought that the following line would resolve the name clash
    using foo::var;   
    

    Well, it does resolve the name clash for the current namespace, which is baz.

    If you move qux into baz, it will prefer foo::var.

    But for ::qux (outside any namespace), there is no reason to prefer baz::var (the alias for foo::var) over bar::var or foo::var, since all of them are in the current namespace search path.

    Even though only using namespace baz; was seen at global level.