Abhijit
Abhijit

Reputation: 63787

Understanding Qualified name lookup for namespace

I would like to understand the namespace qualified name lookup. I am trying to leverage the following

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

to provide a fallback mechanism for a name iff it does not exist in the standard namespace. The following program exemplifies what I am envisaging to achieve

#include <type_traits>
namespace foo
{
    template<class Ty>
    struct remove_extent
        {
        typedef Ty type;
        };
}
namespace fallback
{
    using namespace std;
}
namespace fallback
{
    using namespace foo;
}
template<typename Ty>
struct Bar
{
    typename fallback::remove_extent<Ty>::type var;
};
int main()
{
   Bar<int[]> var;
}

For the first declaration

namespace fallback
{
    using namespace std;
}

S'(fallback, remove_extent) is an empty set so S(fallback, remove_extent) is the union of S(std, remove_extent).

For the second declaration

namespace fallback
{
    using namespace foo;
}

S'(fallback, remove_extent) is non-empty so S(fallback, remove_extent) = S'(fallback, remove_extent) = S(std, remove_extent)

but my compiler thinks otherwise and complains

1>source.cpp(21): error C2872: 'remove_extent' : ambiguous symbol
1>          could be 'source.cpp(6) : foo::remove_extent'
1>          or       'c:\program files (x86)\microsoft visual studio 11.0\vc\include\type_traits(331) : std::remove_extent'

So obviously my understanding is wrong. Why does the compiler includes the name remove_extent from foo?

Upvotes: 0

Views: 231

Answers (1)

ildjarn
ildjarn

Reputation: 62995

For the second declaration ... S'(fallback, remove_extent) is non-empty

No, it isn't:

namespace fallback
{
    using namespace std;
}

After this point, S'(fallback, remove_extent) is empty, so S is S(std, remove_extent).

namespace fallback
{
    using namespace foo;
}

After this point, S'(fallback, remove_extent) is still empty (i.e. there's still no declaration of a remove_extent directly in fallback), so S is now the union of S(std, remove_extent) and S(foo, remove_extent).

template<typename Ty>
struct Bar
{
    typename fallback::remove_extent<Ty>::type var;
};

When we get to this point, there are two entities named remove_extent in fallback (one from std and one from foo, neither declared directly in fallback), so the compiler correctly tells you that the name is ambiguous.

Upvotes: 4

Related Questions