Re: Extending Friendship to Nested Template Class Instantiation
On 18 Mai, 02:47, "ghick...@acm.org" <jghick...@gmail.com> wrote:
class Container;
class Element {
public:
friend class Container;
private:
Element();
};
class Container {
private:
struct Element_arena {
Element* construct() { return new Element(); }
};
Element_arena arena;
public:
Element* make_inner() { return arena.construct(); }
};
If we wanted to apply this Container / Element design pattern to many
different application types, it might be nice to capture the arena
functionality in a template class Arena<T> to be reused in the
implementation of many different kinds of containers. However, the
compiler won't extend a Container's friendship privileges to an
internal (i.e., nested within the Container class definition)
instantiation of Arena<T>. In other words, given the following
changes:
Scenario #2
template<class T>
class Arena {
public:
T* construct() { return new T(); }
};
class Container {
private:
Arena<Element> arena;
public:
Element* make_inner() { return arena.construct(); }
};
Element::Element() is inaccessible to Arena<Element>::construct() even
though Arena<Element> is instantiated within the scope of a
Container. Clearly we wouldn't want arbitrary instantations of
Arena<Element> to have access to an Element's private parts, but it
"seems intuitive" that the compiler could discern Arena<Element>'s
context and allow Scenario#2 above.
I don't think that the compiler should extend friendship
as you whish, because this would totally break the
"access-security" system of C++. Basically you seem to
demand that friendship should be extended to *every type*
that is used as a member of some friend class. This makes
no real sense, because types can be used everywhere (if I
have access to them at this place), so why should we
begin to create a web of friendship-relations to some class,
which often is used as member (or base class?) of some
other class? Please note, that you changed drastically the
situation, by factoring Arena *out* of the container. Arena
just had friend access to Element, because Arena was a
member class (nested class) and not just a member of some
arbitrary type! To create a more reasonable access-right
chain, we start by granting friendship from Element to
Arena<Element>:
template<class>
class Arena;
class Element {
friend class Arena<Element>;
private:
Element();
};
template<class T>
class Arena {
public:
T* construct() { return new T(); }
};
This has of course the effect, that everyone can
simply create an Element by using an instance of
Arena, because Arena is a public available class.
We can create a workaround for this situation by
adding one further layer of indirection, i.e. by
restricting Arena's access granting of member
construct to only to a dedicated ArenaContainer:
template<class>
class ArenaContainer;
template<class T>
class Arena {
private:
friend class ArenaContainer<T>;
T* construct() { return new T(); }
};
template<class T>
class ArenaContainer {
private:
Arena<T> arena;
public:
T* make_inner() { return arena.construct(); }
};
Now you need at least a ArenaContainer<Element>
to legally create an Element instance. Several
adaptions are possible: E.g. if you always need
inheritance to specialize ArenaContainer, you
could make make_inner protected (and either
provide a protected d'tor or a virtual one).
Derived classes could then decide to "publish"
make_inner (by means of a using-declaration) or
not.
Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]