AXIHIXA
AXIHIXA

Reputation: 57

C++ friend operator definition inside class body serves as function declaration?

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

Answers (2)

Alan
Alan

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

songyuanyao
songyuanyao

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

Related Questions