Consider the following clause in [namespace.memdef]/3:
If the name in a
friend
declaration is neither qualified nor a template-id and the declaration is a function or an elaborated-type-specifier, the lookup to determine whether the entity has been previously declared shall not consider any scopes outside the innermost enclosing namespace.
Is there a reason for the exception for template-id along with the qualified name? For that matter, is there a reason for the lookup of an unqualified name that isn't a template-id to be restricted to the innermost enclosing namespace? Is there a specific problem or use-case that this clause solves?
Qualified names and template-ids cannot introduce new members into the enclosing namespace, this is what the note in [namespace.memdef]p3 tries to say:
[ Note: The other forms of
friend
declarations cannot declare a new member of the innermost enclosing namespace and thus follow the usual lookup rules. — end note ]
Therefore, no such restriction is necessary for qualified names and template-ids.
Note that template-ids lack the declaration of the template-parameters, and qualified-ids could introduce names into distant, unrelated namespaces.
This part of the answer is still incomplete, but represents the current state of "research". Feel free to contribute.
The restriction has (probably?) been introduced due to N0783 - Namespace Issues and Proposed Resolutions which "attempts to clarify a number of namespace issues that are currently either undefined or incompletely specified".
This paper from 1995 contains two enlightening discussions of issues related to declarations of entities introduced via friend-declarations. Bear in mind that the name lookup rules back then were different:
(*) The best I could find was N0878 from March 1996, which says "A change was recently made to the working paper to add the “Koenig lookup rule”"
First, the example from N0783 for functions:
void f(char); namespace A { class B { friend void f(char); // ::f(char) is a friend friend void f(int); // A::f(int) is a friend void bf(); }; void B::bf() { f(1); // calls A::f(int); f('x'); // also calls A::f(int) because ::f is hidden } }
The second friend declaration must introduce a new function. N0783 tries to specify in which scope this declaration is introduced. It suggests
All friend declarations for a given name must declare entities in one particular scope.
as a general rule, to avoid the surprises of situations such as the above.
So the question is, which scope do they declare entities in? There are two possibilities, either
- When looking for a previous declaration of the function, look until the nearest enclosing namespace is reached, or
- When looking for a previous declaration, look in all enclosing scopes for the name of the function that was declared. If a previous use of the name is found, the declaration is injected into that scope. If no previous use of the name is found the friend is injected into the nearest enclosing namespace scope.
Rule #2 would mean that the presence of any function called
f
in an enclosing scope, whether or not the types match, would be enough to cause a friend declaration to inject into that scope.I believe that rule #2 is clearly unacceptable. A friend declaration in a namespace would be affected by any global declaration of that name. Consider what this would mean for operator functions! The presence of any
operator+
function in the global scope would force all friendoperator+
operators to appear in the global scope too! The presence of a template in the global scope would have the same effect.
For class types:
namespace N { class A { void f(); }; } using namespace N; namespace M { class B { friend class A; // Without this rule // makes N::A a friend B(); }; class A { void f(); }; } void N::A::f() { M::B b; } // A friend under current rules void M::A::f() { M::B b; } // A friend under proposed rules
Both examples are not as interesting under the current rules because names introduced via friend declarations are only found via ADL. It is possible this restriction is a historical artefact. More "research" is required to follow the development of this restriction after the introduction of ADL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With