Reputation: 57
I'm a newbie reading the C++ Primer book. It says:
A friend declaration only specifies access. It is not a general declaration of the function. If we want users of the class to be able to call a friend function, then we must also declare the function separately from the friend declaration. To make a friend visible to users of the class, we usually declare each friend (outside the class) in the same header as the class itself.
But I just found that this is not the case for friend operator functions defined inside the class body. In the following code, f
could not be found but operator+
is found:
struct X
{
friend void f()
{
// friend functions can be defined in the class
// this does NOT serve as a declaration, even though this is already a definition
// to use this function, another declaration is REQUIRED
}
friend X operator+(const X & x1, const X & x2)
{
// this stuff serves as declaration somehow
return {x1.v + x2.v};
}
void foo()
{
f(); // ERROR: no declaration for f
X tmp = X {1} + X {2}; // CORRECT
}
int v;
};
Could someone tell me what makes this difference? I am using g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, as a reference. I have searched many questions involving friend declaration and definition on StackOverflow but did not find an answer on this. Sorry if this question is duplicated.
Upvotes: 1
Views: 667
Reputation: 1
Even if we define the function inside the class, we must still provide a declaration outside of the class itself to make that function visible. A declaration must exist even if we only call the friend from members of the friendship granting class. This means in your example, you should forward declare the function f
as shown below:
//forward declare f
void f();
struct X
{
//no ADL here since this function f has no parameters of type X. So we also need to declare this outside struct X which we did by providing forward declaration
friend void f()
{
}
void foo()
{
f(); // WORKS NOW because of the forward declaration
X tmp = X {1} + X {2}; //operator+ found using ADL
}
//other members here
};
The output of the program can be seen here.
The reason why the call to operator+
works is because of ADL
which stands for argument dependent lookup. In particular, operator+
can be found using ADL since it has parameters of type X
. So in this case, you do not need to explicitly declare operator+
outside struct X
.
Upvotes: 1
Reputation: 173034
The difference is the operator+
takes X
as parameter, then ADL could find the name; f
takes nothing, ADL can't help any.
(emphasis mine)
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 ordinary name 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.
Upvotes: 2