5

Consider the code:

template<typename T> 
class Foo{};

namespace X
{
    class X{};
}

using namespace X; // now both class X and namespace X are visible
Foo<X::X> f()
{
    return {};
}

int main() {}

gcc5.2 compiles the code with no errors whatsoever. However clang spits the error:

error: 'X' is not a class, namespace, or enumeration Foo f()

error: reference to 'X' is ambiguous

Is the code syntactically valid, according to the C++ standard? Or is just a gcc bug? Removing the qualified name X::X and using Foo<X> instead makes gcc choke also

error: template argument 1 is invalid Foo f()

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • I believe this is answered here: http://stackoverflow.com/questions/5856759/can-a-class-share-a-namespaces-name – GreatAndPowerfulOz Oct 24 '15 at 02:24
  • @Gread.And.Powerful.Oz Thanks, but the 2 answers seem to contradict each other. It will be great if someone can provide a quote from the standard. My question is related to the one we both commented/answered: http://stackoverflow.com/q/33313723/3093378 – vsoftco Oct 24 '15 at 02:27
  • well here's another: http://stackoverflow.com/questions/1539333/using-a-class-in-a-namespace-with-the-same-name and perhaps a google search will help: https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=c%2B%2B%20can%20a%20namespace%20and%20class%20have%20the%20same%20name – GreatAndPowerfulOz Oct 24 '15 at 02:31
  • 1
    @Gread.And.Powerful.Oz Thanks, I've seen some of those before, but I'd like to see what's the answer according to the standard, since one very popular compiler believes it is correct, while another doesn't. None of those answers are giving any clear answer. On the other hand, gcc thinks the code is correct. That's why I also tagged with [language-lawyer](http://stackoverflow.com/questions/tagged/language-lawyer). – vsoftco Oct 24 '15 at 02:36
  • I just had a thought, have you tried Foo<::X::X>?? (Note the leading double colon) – GreatAndPowerfulOz Oct 24 '15 at 02:45
  • @Gread.And.Powerful.Oz Just checked, `::X::X` does it for clang indeed, as it removes any possible ambiguity. It seems that `X::X` is ambiguous for clang, but OK for gcc. I kind of get why the ambiguity, since the compiler may believe that `X::X` refers either to the member of the class `X` or to the namespace `X` itself. However I don't know for sure that the code is invalid, since gcc compiles it. – vsoftco Oct 24 '15 at 02:47
  • Related to http://stackoverflow.com/questions/29883977/ambiguous-name-lookup-with-using-directive – Columbo Oct 24 '15 at 12:40

2 Answers2

3

[namespace.udir]/6:

If name lookup finds a declaration for a name in two different namespaces, and the declarations do not declare the same entity and do not declare functions, the use of the name is ill-formed.

For the first X in X::X, both the namespace and the class are considered. However, the name of the namespace resides in the global namespace while the class resides in namespace X; Hence the above quote applies, Clang is therefore correct. (This also occurs when just writing X, clearly).

::X removes this ambiguity. Lookup does not proceed into the namespace anymore. [namespace.qual]/2:

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, […]

Here, X is the global namespace and m is "X". Clearly, the declaration of our namespace is found, so lookup is definite here.

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • Thanks. I wonder whether I should fill a gcc bug, since the standard doesn't say "no diagnostic required" in this case. – vsoftco Oct 24 '15 at 14:20
  • @vsoftco Yes, please. Although I think I there might already exist one (but I'd rather just submit it than run the risk of it not being reported at all) – Columbo Oct 24 '15 at 14:21
1

Not a complete answer but that is a clear situation that shows even declaring using namespace, for objects with the same name as the namespace you need to declare the namespace.

#include <iostream>
#include <string>

namespace test
{
    void function1(void){std::cout << "Function inside the namespace" << std::endl;}

    class test
    {
    public:
        static void function1(void){std::cout << "Function inside the class" << std::endl;}    
    };
};

using namespace test;

int main()
{
    function1();

    test::function1();

    test::test::function1();
}

Output (GCC 4.9.2)

"Function inside the namespace"
"Function inside the namespace"
"Function inside the class"
Captain Wise
  • 480
  • 3
  • 13