Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

problems with friends ... ;-)

47 views
Skip to first unread message

Christof Warlich

unread,
Jan 20, 2016, 2:46:09 AM1/20/16
to
Hi,

can anyone tell what's wrong with the friend declaration below and how to do it properly?

$ cat tst.cpp
template<typename T> class B;
class A {
class Inner {};
friend class B<Inner>;
};
template<typename T> class B {};
class Derived: public B<A::Inner> {};

$ g++ -c tst.cpp
tst.cpp:3:11: error: 'class A::Inner' is private
class Inner {};
^
tst.cpp:9:23: error: within this context
class Derived: public B<A::Inner> {};
^

Thanks for your kind attention,

Chris

Alf P. Steinbach

unread,
Jan 20, 2016, 4:43:16 AM1/20/16
to
On 1/20/2016 8:45 AM, Christof Warlich wrote:
>
> $ cat tst.cpp
> template<typename T> class B;
> class A {
> class Inner {};
> friend class B<Inner>;
> };
> template<typename T> class B {};
> class Derived: public B<A::Inner> {};
>
> $ g++ -c tst.cpp
> tst.cpp:3:11: error: 'class A::Inner' is private
> class Inner {};
> ^
> tst.cpp:9:23: error: within this context
> class Derived: public B<A::Inner> {};
> ^
>
> Thanks for your kind attention,

The error message says that `A::Inner` is private.

Checking the definition of `A`, sure, class `A::Inner` is private, so
you can't normally access it or refer to it from other code than `A`.

It's private because `private` access is the default for `class`. If you
want `public` access as default, use a `struct`.


Cheers & hth.,

- Alf

Öö Tiib

unread,
Jan 20, 2016, 5:10:06 AM1/20/16
to
Perhaps you misunderstand to whom and what access the 'friend' keyword
grants. The 'B<A::Inner>' has access to everything in 'A' thanks to that
'friend'. 'Inner' has access to everything in 'A' anyway, no need to 'friend' it.
The 'Derived' does not have access to private components of 'A' so can't
use 'A:Inner' and so can't define 'B<A:Inner>' as its base class.
That is what the compiler complains about.

Christof Warlich

unread,
Jan 20, 2016, 5:45:56 AM1/20/16
to
Am Mittwoch, 20. Januar 2016 11:10:06 UTC+1 schrieb Öö Tiib:
> Perhaps you misunderstand to whom and what access the 'friend' keyword
> grants. The 'B<A::Inner>' has access to everything in 'A' thanks to that
> 'friend'.

This is why I was puzzled that I got the error message: As I made B<A::Inner> a friend of A, why does the compiler complain? Looks like using A::Inner as a template parameter requires access permissions to Inner from global scope, not from B<A::Inner>.

But even after this insight, the second part of my question remains: How to do it properly, i.e. how can I avoid the compile time error _without_ making class Inner public?



Alf P. Steinbach

unread,
Jan 20, 2016, 6:03:46 AM1/20/16
to
On 1/20/2016 11:45 AM, Christof Warlich wrote:
> Am Mittwoch, 20. Januar 2016 11:10:06 UTC+1 schrieb Öö Tiib:
>> Perhaps you misunderstand to whom and what access the 'friend'
>> keyword grants. The 'B<A::Inner>' has access to everything in 'A'
>> thanks to that 'friend'.
>
> [snip]
> How to do it properly, i.e. how can I avoid the compile time error
> _without_ making class Inner public?

You just need to make the right friends instead of the wrong friends.

I.e., make `Derived` a `friend` of `A`, so that it can access `A::Inner`.

The public class' public inheritance from private `A::Inner` is,
however, a design smell – are you sure this is what you want?

Alf P. Steinbach

unread,
Jan 20, 2016, 6:06:33 AM1/20/16
to
On 1/20/2016 12:03 PM, Alf P. Steinbach wrote:
> [snip]
> The public class' public inheritance from private `A::Inner` is,
> however, a design smell – are you sure this is what you want?

Oh, sorry, it's just a template parameter of the base class type.

Still, it looks a bit weird, like a solution to some other unmentioned
problem?


Cheers,

- Alf


Öö Tiib

unread,
Jan 20, 2016, 6:24:28 AM1/20/16
to
On Wednesday, 20 January 2016 12:45:56 UTC+2, Christof Warlich wrote:
>
> But even after this insight, the second part of my question remains: How to do it properly, i.e. how can I avoid the compile time error _without_ making class Inner public?

Hard to tell what you want to make public or what not. However I try to
use deductive logic. Since 'B<A::Inner>' is public base class (so those
base objects of 'Derived' objects are public) you most likely want to
make type of those ('B<A::Inner>') also public. IOW:

template<typename T> class B;
class A {
class Inner {};
public:
using Binner = B<Inner>;
};
template<typename T> class B {};
class Derived: public A::Binner {};

Christof Warlich

unread,
Jan 20, 2016, 6:26:40 AM1/20/16
to
Am Mittwoch, 20. Januar 2016 12:06:33 UTC+1 schrieb Alf P. Steinbach:
> Oh, sorry, it's just a template parameter of the base class type.

Yeah, making Derived a friend did not do the trick. So there is really no way except of making Inner public?

>
> Still, it looks a bit weird, like a solution to some other unmentioned
> problem?

Well, I'm extending std::thread to accept an additional parameter, i.e. POSIX attributes, and B:<Inner> in reality is a member from the std namespace that I cannot change.

>
>
> Cheers,
>
> - Alf

Alf P. Steinbach

unread,
Jan 20, 2016, 6:56:25 AM1/20/16
to
On 1/20/2016 12:26 PM, Christof Warlich wrote:
> Am Mittwoch, 20. Januar 2016 12:06:33 UTC+1 schrieb Alf P.
> Steinbach:
>> Oh, sorry, it's just a template parameter of the base class type.
>
> Yeah, making Derived a friend did not do the trick. So there is
> really no way except of making Inner public?

This compiles nicely with g++ 4.8.2 and MSVC 2015:

template<typename T> class B;

class A {
class Inner {};
friend class Derived;
};

template<typename T> class B {};

class Derived: public B<A::Inner> {};

auto main() -> int
{
Derived x;
(void) x;
}


>> Still, it looks a bit weird, like a solution to some other
>> unmentioned problem?
>
> Well, I'm extending std::thread to accept an additional parameter,
> i.e. POSIX attributes, and B:<Inner> in reality is a member from the
> std namespace that I cannot change.

Ah.

Alf P. Steinbach

unread,
Jan 20, 2016, 6:58:04 AM1/20/16
to
On 1/20/2016 12:56 PM, Alf P. Steinbach wrote:
>
> This compiles nicely with g++ 4.8.2 and MSVC 2015:

Dang, 5.1.0


Christof Warlich

unread,
Jan 20, 2016, 7:22:25 AM1/20/16
to
I still get the same error with gcc 4.8.4. Interesting to know that it works with gcc 5.1.0 and MSVC 2015.

Christof Warlich

unread,
Jan 20, 2016, 7:24:40 AM1/20/16
to
Thanks, that works with gcc 4.8.4, so that seems to be what I was looking for :-).

Marcel Mueller

unread,
Jan 20, 2016, 4:54:26 PM1/20/16
to
First of all Derived need to be your friend rather than B<> that does
not know anything about A::Inner.
But this is still not sufficient because B<> is a public base class that
cannot be accessed from public since the template parameter is non
public. But even with private inheritance it does not work. I have no
idea why.

In contrast an aggregation
class Derived { public B<A::Inner> TheB; };
works if you declare Derived as friend.

Marcel
0 new messages