c++c++17language-lawyerfriendusing-directives

Can a name introduced via using-directive or using-declaration be used as elaborated-type-specifier of a friend declaration?


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?


Solution

  • 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).