Question

From section 7.3.4.2 of the c++11 standard:

A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. [ Note: In this context, “contains” means “contains directly or indirectly”. —end note ]

What do the second and third sentences mean exactly? Please give example.

Here is the code I am attempting to understand:

namespace A
{
    int i = 7;
}
namespace B
{
    using namespace A;
    int i = i + 11;
}
int main(int argc, char * argv[])
{
    std::cout << A::i << " " << B::i << std::endl;
    return 0;
}

It print "7 7" and not "7 18" as I would expect.

Sorry for the typo, the program actually prints "7 11".

Was it helpful?

Solution

Eliminating the undefined behaviour:

namespace A
{
    int i = 7;
}
namespace B
{
    using namespace A;
    int tmp = i + 11;
    int i = tmp;
}
#include <iostream>
int main()
{
    std::cout << A::i << " " << B::i << std::endl;
    return 0;
}

The meaning of the standard is that at the line

    int tmp = i + 11;

the name i appears in the "nearest enclosing namespace which contains both the using-directive and the nominated namespace"; the using-directive appears in namespace B while the nominated namespace is namespace A; the nearest enclosing namespace is the global namespace, so i appears as ::i. This means that if a name i is already present in the global namespace the code is ambiguous.

For a more complex example:

namespace A {
    namespace B {
        namespace C {
            int i = 4;
        }
    }
    namespace D {
        using namespace B::C;
        namespace E {
            int j = i;
        }
    }
}

At the line int j = i, i appears in the nearest enclosing namespace of the using-directive (i.e., A::D) and the nominated namespace (A::B::C), which is A. So, within A::D after the using-directive, and so also within A::D::E, the unqualified name i can refer to A::B::C::i appearing as A::i, shadowing any ::i, conflicting with any A::i, and being shadowed by any A::D::i or A::D::E::i (within A::D::E):

int i = 1;                // shadowed by A::B::C::i appearing as A::i
namespace A {
    int i = 2;            // conflicts with A::B::C::i appearing as A::i
    namespace B {
        int i = 3;        // irrelevant
        namespace C {
            int i = 4;    // nominated; appears as A::i
        }
    }
    namespace D {
        int i = 5;        // shadows A::B::C::i appearing as A::i
        using namespace B::C;
        namespace E {
            int i = 6;    // shadows A::B::C::i appearing as A::i
            int j = i;
        }
    }
}

Note that just because the name appears as A::i during unqualified name lookup, that does not mean that it actually is there; the qualified name A::i will continue to refer only to an actual name A::i (if any exists).

OTHER TIPS

The using statement in your code is irrelevant. B::i is already in scope when the initializer for B::i is evaluated. You can trivially prove this by deleting the using statement; your code should compile and run just the same. In any case, the value of B::i ends up being undefined because it depends on an uninitialized value (i.e. the value that B::i had when the initializer was evaluated).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top