Ambiguous reference to namespace within an inline namespace

1.7k Views Asked by At

Assume the following code:

namespace test 
{ 
    namespace detail 
    { 
    }

    inline namespace v1 
    { 
        namespace detail 
        { 
            void foo() 
            { 
            }
        }
    }
}

int main()
{ 
    test::detail::foo(); 
}

As we can see, this code compiles with Clang; not with GCC, however - GCC complains that the reference to namespace detail is ambiguous:

main.cpp:20:11: error: reference to 'detail' is ambiguous
     test::detail::foo(); 
           ^
main.cpp:4:5: note: candidates are: namespace test::detail { }
     { 
     ^
main.cpp:10:9: note:                 namespace test::v1::detail { }
         { 
         ^

Which compiler does the correct thing here?

2

There are 2 best solutions below

0
On BEST ANSWER

GCC is correct:

Members of an inline namespace can be used in most respects as though they were members of the enclosing namespace. Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup (3.4.2) whenever one of them is, and a using-directive that names the namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace (7.3.1.1). Furthermore, each member of the inline namespace can subsequently be explicitly instantiated (14.7.2) or explicitly specialized (14.7.3) as though it were a member of the enclosing namespace. Finally, looking up a name in the enclosing namespace via explicit qualification (3.4.3.2) will include members of the inline namespace brought in by the using-directive even if there are declarations of that name in the enclosing namespace.

(This is at 7.3.1/8 in old n3337 numbering)

I believe you're seeing Clang bug #10361.

0
On

GCC is correct.

N3797 states that,

and a using- directive ( 7.3.4 ) that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace ( 7.3.1.1 ).

Thus, test::detail is not the same namespace as test::v1::detail, so the lookup of test::detail is ambiguous. The Standard is exceptionally clear that the lookup of test::detail should include test::v1::detail, there are many quotes in this section to support this, but nothing to state that they should be considered the same namespace.

Arguably, I would say that Clang's behaviour is superior, but GCC's is correct.