Friend function definition standard wording

1,582 views
Skip to first unread message

razvyb...@gmail.com

unread,
Mar 24, 2019, 7:08:59 AM3/24/19
to ISO C++ Standard - Discussion
n the current draft of the C++ standard (march 2019) [class.friend] p.6 states (emphasis mine):

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. [...]
 

What does "the function has namespace scope" mean?

The only situation that I could come up with in which the function does not have namespace scope is the following:


struct A
{
   
static void f();

   
struct B
   
{
       
friend void f() {};
   
};
};



However neither clang nor gcc associate the friend definition inside B to the static method inside A, the friend definition is associated to a function that belongs to the global namespace.

Balog Pal

unread,
Mar 26, 2019, 10:30:46 AM3/26/19
to ISO C++ Standard - Discussion, razvyb...@gmail.com
I'm lost on what the question really is.

You can define friend functions right inside the class. But such a function is placed is placed outside the class, in the enclosing namespace.

Say in your example add friend operator < (A, A) {};  that operator is nonmember and placed in the namespace.
If you provide definition, then the function the friend applies to that very defined function, nothing else in or out the class.
If you do not provide definition, then the (unqualified) function the friend applies to a namespace function defined outside, never to a class member. If you want to befriend that static f, spell  friend A::f;

razvyb...@gmail.com

unread,
Mar 26, 2019, 11:17:55 AM3/26/19
to ISO C++ Standard - Discussion, razvyb...@gmail.com
The question is why is the condition "the function has namespace scope" specified in [class.friend] p.6. Initially I thought that it is redundant, because:
  • if this is the first declaration of the function, it will be introduced in the nearest enclosing namespace, therefore it will have "namespace scope"
  • otherwise, the unqualified-id may find only a "namespace scope" function
 
But then I came up with the example in my original question, in which the search for the unqualified-id may find a "class scope" function. This is because [namespace.memdef] p.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. [...]"

can be read as:

    "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 is done in all scopes between the declaration and the innermost enclosing namespace (but not outside the innermost enclosing namespace".

So,
  • is the condition "the function has namespace scope" in [class.friend] p.6 redundant and [namespace.memdef] p.3 must be read as: "the lookup is done only in the innermost enclosing namespace's scope"
  • or is the condition correct, [namespace.memdef] p.3 is read as "the lookup is done in all scopes between the declaration and the innermost enclosing namespace (but not outside the innermost enclosing namespace" and the compilers are wrong?

Alberto Barbati

unread,
Mar 27, 2019, 6:49:08 AM3/27/19
to ISO C++ Standard - Discussion, razvyb...@gmail.com

Il giorno martedì 26 marzo 2019 16:17:55 UTC+1, razvyb...@gmail.com ha scritto:
So,
  • is the condition "the function has namespace scope" in [class.friend] p.6 redundant and [namespace.memdef] p.3 must be read as: "the lookup is done only in the innermost enclosing namespace's scope"
  • or is the condition correct, [namespace.memdef] p.3 is read as "the lookup is done in all scopes between the declaration and the innermost enclosing namespace (but not outside the innermost enclosing namespace" and the compilers are wrong?

There are a lot of CWG issues related with friend declarations (see for example 138 and related issues). Some of them appears to be still pending, despite the old age. Yours seems just another case...

I'm not a language lawyer, but for what it's worth, I believe option 2 (the compilers are wrong) is the correct one. The rationale is that in the following amended example:

struct A
{
   
static void f();

   
struct B
   
{
       
friend void f() {}


       
void g()
       
{
            f
(); // resolves to A::f(), which hides ::f()
       
}
   
};
};

Since the f() in B::g() looks up and calls A::f(), the friend declaration in B should also look up A::f() for consistency. The code would thus be ill-formed because the friend declaration provides a definition but A::f() does not have namespace scope.
 
Just my two eurocent,

razvyb...@gmail.com

unread,
Mar 27, 2019, 10:44:04 AM3/27/19
to ISO C++ Standard - Discussion, razvyb...@gmail.com
Ok, so you think that the standard is correct (the condition "the function has namespace scope" in [class.friend] p.6 is not redundant and [namespace.memdef] p.3 should be read as "the lookup is done in all scopes between the declaration and the innermost enclosing namespace"). Therefore the compilers are wrong.

Thank you for your input.
Reply all
Reply to author
Forward
0 new messages