Why do gcc, clang and msvc successfully compile the following code? (godbolt)
namespace impl {
class A;
} // namespace impl
namespace api {
using namespace impl;
} // namespace api
class B
{
friend class api::A; // (1)
};
The way I see it, this particular kind of friend declaration requires elaborated-type-specifier. Elaborated-type-specifier is class
keyword followed by class name. But there's no class with the name api::A
in this translation unit. Using-directive doesn't declare such class, it only affects name lookup rules. So I would expect that compilation of line marked (1)
fails with error that there's no class
A in namespace api
. But major compilers accept it... What am I missing?
And the followup question: if I replaced using-directive using namespace impl;
with using-declaration using impl::A;
, that would really declare name A
in namespace api
, thus making the code well-formed?
First of, class api::A
in your friend
declaration is an elaborated-type-specifier.
But regardless, even if you drop class
so that it isn't an elaborated-type-specifier anymore, lookup of names in a friend
declaration is done just like any other lookup. Lookup of names (whether qualified or unqualified) in an elaborated-type-specifier is also done as usual. (There are specific rules in each case, but none which matter here.)
Only if lookup for an unqualified name in an elaborated-type-specifier doesn't find anything or if the whole declaration has certain specific forms in which the elaborated-name-specifier is the whole declaration, then it declares a class/enum with the name in some target scope.
Lookup for api::A
from the class scope finds ::impl::A
and so the friend declaration refers to that class (whether or not the class
keyword is used).