Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaring protected function friend

Does A::foo need to be declared public for B to declare it friend?

class A {
    protected:  // public ?
        void foo(int x);
};

class B : public A {
    friend void A::foo(int);  // not fine with GCC 4.8.1 but fine with VS 2013
    void goo(int x) {foo(x);}  // fine
    static void hoo(int x) {}
};

void A::foo(int x) {B::hoo(x);}  // friend declaration needed for this

Visual Studio 2013 thinks it is fine if A::foo is protected, but GCC 4.8.1 thinks it's not and wants it to be public. Which compiler is correct? My initial instinct was that it can be declared protected. After all, B is derived from A, so should have access to A::foo (as B::goo demonstrates trivially).

like image 260
prestokeys Avatar asked Nov 01 '22 19:11

prestokeys


1 Answers

VS is correct here.

The name A::foo is in fact accessible in the scope of B since it's publicly derived from A. To prove this, consider

class A {
    protected:
        void foo(int x);
};

class B : A {
    using A::foo; // it's OK to refer to the name A::foo
};

void A::foo(int x) {}  

So by using the quote § 11.3 [friend functions]

A name nominated by a friend declaration shall be accessible in the scope of the class containing the friend declaration.

we can argue that's there's no violation of the rules (foo is also protected in the derived class).

It seems like in gcc, once the friend keyword is placed in front of the friend function declaration, name lookup starts ignoring inheritance (nothing to do though with friendship not being inheritable)


As mentioned by 40two in the comments the same error is emitted from Clang and there's a bug report for it; this issue is also reffered to DR209. It seems that for the implementers to get this right is quite hard.

like image 96
Nikos Athanasiou Avatar answered Nov 08 '22 10:11

Nikos Athanasiou