Home > Software engineering >  C friend operator definition inside class body serves as function declaration?
C friend operator definition inside class body serves as function declaration?

Time:02-11

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.

CodePudding user response:

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.

CodePudding user response:

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 function has no parameters. 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. So in this case, you do not need to explicitly declare operator outside struct X.

  • Related