what normative text governs that a friend defined in a class can be found by a non-adl lookup only once re-declared in the enclosing namespace?

All standard references below, unless explicitly noted otherwise, refer to N4659: March 2017 post-Kona working draft/C++17 DIS.


Friend declarations (definition or not) does not introduce new names into the enclosing namespace

[class.friend]/6 governs the scope of a “hidden friend” (only declared and defined at its friend declaration) [emphasis mine]:

[class.friend]/6: A function can be defined in a friend declaration of a class if and only if the class is a non-local class ([class.local]), the function name is unqualified, and the function has namespace scope.

Thus, even if the definition of the function is located at its friend declaration, the friend function has namespace scope and can be explicitly exposed to regular lookup by (re-)declaration in the enclosing namespace (of the class in which it is defined).

#include <iostream>

namespace a {
struct A {
    // Definition of 'a::foo()' (note the namespace scope).
    friend void foo() { std::cout << __PRETTY_FUNCTION__; }   
};

// (re-)declaration of foo().
void foo();
}  // namespace 'a'

int main() {
    a::foo();  // void a::foo()
}

The more general and interesting question to ask is, however

  • What governs that a friend declaration does not introduce/bind the name of the declaration to the namespace scope?

Which is governed by [namespace.memdef]/3

[namespace.memdef]/3: If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup ([basic.lookup.unqual]) or qualified lookup ([basic.lookup.qual]). [ Note: The name of the friend will be visible in its namespace if a matching declaration is provided at namespace scope (either before or after the class definition granting friendship).  — end note ] […]

Thus, it is not relevant here that the function is defined at the friend declaration, but rather that a friend declaration (even when not containing a definition) does not introduce the name into the namespace scope; in the following example lookup similarly fails to find the name from the friend declaration:

#include <iostream>

namespace a {
struct A {
    friend void bar(); 
};
}  // namespace 'a'

int main() {
    a::bar();  // error: no member named 'bar' in namespace 'a'
}

We may also note that the C++20 draft, N4861 (March 2020 post-Prague working draft/C++20 DIS) has added a paragraph, albeit non-normative, that explicitly mentions this; from [basic.scope.pdecl]/13 [emphasis mine]:

[ Note: Friend declarations refer to functions or classes that are members of the nearest enclosing namespace, but they do not introduce new names into that namespace ([namespace.memdef]). […]

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top