名称空间与包含的名称相同 class,gcc 可以,clang 不行

Namespace having the same name as contained class, ok for gcc, not ok for clang

考虑代码:

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 编译代码没有任何错误。然而 clang 吐出错误:

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

error: reference to 'X' is ambiguous

根据 C++ 标准,代码在语法上是否有效?或者只是一个 gcc 错误?删除限定名称 X::X 并改用 Foo<X> 也会使 gcc 阻塞

error: template argument 1 is invalid Foo f()

不是一个完整的答案,但这是一个明确的情况,表明即使声明使用命名空间,对于与命名空间同名的对象,您也需要声明命名空间。

#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();
}

输出 (GCC 4.9.2)

"Function inside the namespace"
"Function inside the namespace"
"Function inside the class"

[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.

对于 X::X 中的第一个 X,命名空间和 class 都会被考虑。但是,命名空间的名称驻留在全局命名空间中,而 class 驻留在命名空间 X 中;因此上面的引用适用,因此 Clang 是正确的。 (这也发生在只写 X 时,很明显)。

::X 消除了这种歧义。查找不再进入命名空间。 [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, […]

这里,X是全局命名空间,m是"X"。很明显,我们的命名空间的声明是找到了,所以这里查找是肯定的。