Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Regarding friend function definition and namespace scopes

I was reading this blog post section, and I tried to play around with the snippet that was provided.

namespace N {
// 2
class A {
friend void f(A) {} // 1
};
}

If I understood correctly, the definition in // 1 will inject the name f where // 2 is located. However it will only be available via argument-dependent lookup. Fine.

There is a sentence in the post that caught my attention:

7.3.1.2/3 Namespace member definitions [namespace.memdef]p3

Every name first declared in a namespace is a member of that namespace. 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 (3.4.1) or qualified lookup (3.4.3).

Notice that nowhere is it stated that the name introduced by a friend-declaration must have any particular relation to name of the class it is declared and/or defined in, or any particular relation to the class at all (for that matter).

From this, I thought the following snippet would have been valid:

namespace N {
struct A {
};

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

int main() {
  N::A a;
  f(a);
}

But it's rejected by both GCC7 and Clang 4.

t.cpp:19:3: error: ‘f’ was not declared in this scope

The funny thing is that, when I try to call f with a N::B object, I get the following error:

t.cpp:12:6: error: could not convert ‘b’ from ‘N::B’ to ‘N::A’

So here's my question:

Shouldn't f(A) be detected via ADL? Since both classes are in the namespace I don't see why this fails. I looked in the standard the section about friends, but failed to find a relevant section.

I wonder in which scope f(A) was injected, since GCC is able to find it when I try to give the wrong argument type via calling f(B).

like image 334
Dante Avatar asked Sep 06 '17 11:09

Dante


People also ask

What is the scope of friend function?

If the friend function is a member of another class, you need to use the scope resolution operator ( :: ). For example: class A { public: int f() { } }; class B { friend int A::f(); }; Friends of a base class are not inherited by any classes derived from that base class.

What is the scope of a namespace?

A scope is the portion of a program from where a namespace can be accessed directly without any prefix. At any given moment, there are at least three nested scopes.

What do you mean by friend function?

In object-oriented programming, a friend function, that is a "friend" of a given class, is a function that is given the same access as methods to private and protected data. A friend function is declared by the class that is granting access, so friend functions are part of the class interface, like methods.

What do you mean by friend function in C++?

A friend function is a function that isn't a member of a class but has access to the class's private and protected members. Friend functions aren't considered class members; they're normal external functions that are given special access privileges.


1 Answers

From cppreference/cpp/language/friend:

A name first declared in a friend declaration within class or class template X becomes a member of the innermost enclosing namespace of X, but is not accessible for lookup (except argument-dependent lookup that considers X) unless a matching declaration at the namespace scope is provided - see namespaces for details.


From cppreference/cpp/language/namespace:

Names introduced by friend declarations within a non-local class X become members of the innermost enclosing namespace of X, but they do not become visible to lookup (neither unqualified nor qualified) unless a matching declaration is provided at namespace scope, either before or after the class definition. Such name may be found through ADL which considers both namespaces and classes.


This is consistent with your example - f takes an A, which is not the same type as the enclosing class.

If you change your example to...

namespace N {
struct A {
};

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

int main() {
  N::B b;
  f(b);
}

...it will compile.


Related standard quote:

$14.3 [class.friend]

A friend of a class is a function or class that is given permission to use the private and protected member names from the class. [...] 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. [...] Such a function is implicitly an inline function. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not ([basic.lookup.unqual]).

like image 128
Vittorio Romeo Avatar answered Sep 29 '22 22:09

Vittorio Romeo