6

In 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 both clang and gcc do not associate the friend definition inside B to the static method inside A, but to a function that belongs to the global namespace.

Are there other situations I am missing?

2 Answers 2

3

I think that you have actually answered your own question, but without realizing it.

"The function has namespace scope" means that it is part of a namespace, not part of a class or struct. So the function A::B::f() doesn't exist. And it doesn't refer to A::f() either. Instead, the function you have defined as the friend is actually the function ::f(), since that is the namespace that it resides in (the global namespace).

I suspect (but have not tried), that if you wrap all of this in a namespace, then the f() you are defining would be a part of that namespace. So, for example,

namespace ns {
    struct A
    {
        static void f();

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

would define the friend function as the function ns::f().

Sign up to request clarification or add additional context in comments.

11 Comments

I think the friend definition should not define ns::f, because the standard says: "A name nominated by a friend declaration shall be accessible in the scope of the class containing the friend declaration.". So it first searches for a function, it finds it, and because the friend declaration is actually a definition, the program should not compile, instead of defining ns::f.
@user42768 "Accessible" in the Standard refers to public/protected/private access levels. That sentence is saying that a class X can have friend void Y::g(); only if the name Y::g is public, or protected and X inherits Y, or Y declares class X as a friend. (This case can't also be a definition.)
A friend definition is, first and foremost, a declaration. Declarations introduce names, they (normally) don't lead to lookup of the name being declared. I think what applies here is [namespace.memdef]/3, based on which it would seem that above friend declaration indeed contains a definition of ns::f, and the one in your original example simply defines the function ::f. You can verify this by simply adding a definition of ::f() and observing that this will lead to an error in compilation due to redefinition…
Also worth noting: A function definition marked friend does define a namespace member as explained, but it doesn't actually by itself declare that function in the namespace. So after this example, you can't call ns::f();. But if you add the declaration void f(); in the namespace or void ns::f(); outside the namespace, it names the same function that was already defined, and so it can be called.
However, it would seem that this, unfortunately, doesn't really answer the original question which is about why the restriction that the function have namespace scope exists in the first place!?
|
0

Looking for the relevant rule that says a friend definition of an unqualified function name is always a namespace member, I found that's not quite the case. [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. ... 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.

The requirement in question applies only to function definitions, and rules out a local befriending class or a qualified friend name. But that leaves the possibility of a template-id as the function name.

So the wording seems to make a difference in this code:

struct A {
    template <typename T>
    static void f();

    template <typename T>
    struct B {
        friend void f<T>() {}
    };
};

Here the name in the friend declaration is a template-id, so the rule about skipping non-namespace scopes does not apply, and f really names the function template A::f. So [class.friend]/6 says this is ill-formed, though if the friend declaration were not a definition, it would be well-formed.

6 Comments

"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 to say that the lookup considers all scopes between the friend declaration and the innermost enclosing namespace, but not any scope outside (the opposite of inside, not a synonym for "except") of that scope.
Also, would the friend definition inside B define an explicit specialization of f? Then it would require the template<> syntax. There are other rules to forbid that, such as: "An explicit specialization shall be declared in the namespace of which the template is a member, or, for member templates, in the namespace of which the enclosing class or enclosing class template is a member.".
The friend definition is not defining an explicit specialization, because "explicit specialization" is defined as a declaration that starts with template<>. It's just a "definition of a function template specialization". Of course there is no such thing, but the rules allow a friend declaration to name a function template specialization without implying it is explicitly specialized or instantiated, and [class.friend]/6 is the only spot I see that says such a declaration may not be a definition.
Ok, but consider the following example: wandbox.org/nojs/gcc-head/permlink/zDsAt43GCW3HSxV4. [class.friend]/6 does not apply, but the program is still ill-formed. I think that both the examples are invalided by the fact that you cannot define a template specialization and it has nothing to do with them being friend declarations.
I see your point about the [namespace.memdef]/3 scope rule, but that just brings up the additional question of why compilers see the friend in your original example as a new ::f, not a redeclaration of A::f. And yeah, the non-template-id friend definition is another good point. I still don't see anything that would explicitly forbid that, but maybe it's implied to be invalid by omission, compared to the parts saying that explicit specializations and explicit instantiations "can be" declared.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.