Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested anonymous namespaces

It is legal in C++ to declare nested anonymous namespaces in the following manner:

namespace {
    namespace {
        struct Foo
        {
        };
    }
}

namespace {    
    struct Foo // SAME IDENTIFIER AS <unnamed>::<unnamed>::Foo!!!
    {
    };
}

However, how would you declare an identifier using an explicitly typed Foo to avoid ambiguity?

EDITED -- for all of you who do not read the question.

p.s. I have no intentions to use this sort of constructs, but I need to understand whether it is possible to disambiguate Foo in case someone finds a legitimate use for it. My compiler extension needs to handle all cases.

like image 419
Zach Saw Avatar asked Oct 07 '22 04:10

Zach Saw


1 Answers

The C++ standard states it pretty clearly in 7.3.1.1p1:

An unnamed-namespace-definition behaves as if it were replaced by

inline(opt) namespace unique { /* empty body */ }
using namespace unique ;
namespace unique { namespace-body }

where inline appears if and only if it appears in the unnamed-namespace-definition, all occurrences of unique in a translation unit are replaced by the same identifier, and this identifier differs from all other identifiers in the entire program.

So from above, we know that your code actually translates to the following:

namespace unique1 {}
using namespace unique1;
namespace unique1 {
    namespace unique2 {}
    using namespace unique2;
    namespace unique2 {

        struct Foo
        {
        };

    }
}

namespace unique3 {}
using namespace unique3;
namespace unique3 {

    struct Foo
    {
    };

}

Therefore, your first Foo can only be accessed within namespace unique1 and the second Foo can be accessed in the global namespace due to using namespace unique3;. I was wrong. Corrected by comments below.

Then from 7.3.4p4:

For unqualified lookup (3.4.1), the using-directive is transitive: if a scope contains a using-directive that nominates a second namespace that itself contains using-directives, the effect is as if the using-directives from the second namespace also appeared in the first.

Therefore, when you refer to Foo, it can mean either unique1::unique2::Foo or unique3::Foo, which is an error. Note that the other answer says: has hidden unique name that cannot be accessed. This is incorrect, they can be accessed due to the using directives, it is just that both names are visible.

However, by prepending the scope resolution operator :: to Foo you can access unique3::Foo because of the following:

From 3.4.3.2p2:

For a namespace X and name m, the namespace-qualified lookup set S(X,m) is defined as follows: Let S0(X,m) be the set of all declarations of m in X and the inline namespace set of X (7.3.1). If S0(X,m) is not empty, S(X,m) is S0(X,m); otherwise, S(X,m) is the union of S(Ni,m) for all namespaces Ni nominated by using-directives in X and its inline namespace set.

The emphasized part says using-directives in X, which in your case means using namespace unique1; and using namespace unique3;, so the namespace-qualified lookup set looks like this: S(unique3::Foo), which means unique1::unique2::Foo is not included in the set and therefore is not an error.

like image 58
Jesse Good Avatar answered Oct 10 '22 02:10

Jesse Good