Make all derived template classes friend of other class in C++

851 Views Asked by At

Let's say I have to following hierarchy:

template<class T> class Base {
protected:
    T container;
};

template<class T> class Derived1 : public Base<T> {
public:
    void f1() {
        /* Does stuff with Base<T>::container */
    }
};

template<class T> class Derived2 : public Base<T> {
public:
    void f2() {
        /* Does stuff with Base<T>::container */
    }
};

Now I want an independent Class (not derived from Base) that can access the Base<T>::container directly from Base or any Derived class. I read about template friend classes and it seems to be the solution to my problem but I couldn't figure out the syntax yet. I am looking for something like:

template<class T> class Foo{
    template<T> friend class Base<T>; // <-- this does not work
public:
    size_t bar(const Base<T> &b) const{
        return b.container.size();
    }
};

Derived1<std::vector<int> > d;
d.f1();
Foo<std::vector<int> > foo;
size_t s = foo.bar()

The friend class line causes an error: specialization of ‘template<class T> class Base’ must appear at namespace scope template<T> friend class Base<T> and the member variable container is still not accessible.

2

There are 2 best solutions below

0
On BEST ANSWER

A couple of issues:

Just as you don't put a <T> after the class name when defining a class template:

template <class T> class X<T> { ... }; // WRONG
template <class T> class X { ... };    // RIGHT

you shouldn't put it after the class name when declaring a class template, whether in a forward declaration or friend declaration:

template <class T> class X<T>; // WRONG
template <class T> class X;    // RIGHT - declares the template exists
template <class T> friend class X<T>; // WRONG
template <class T> friend class X;    // RIGHT - says all specializations of X are friends

(Unless you're creating a class template partial specialization. For example, if class template X is already declared, then template <class T> class X<T*> { ... }; defines a partial specialization that will be used instead of the primary template when the template argument is a pointer.)

And you have the friend declaration backwards: it needs to appear inside the class with the non-public member(s), and name the other class(es) which are allowed to use the members. (If it worked the other way around, then any new class could gain access to any other class's private and protected members, without the permission of the owning class!)

So you would need:

template <class T> class Foo;

template<class T> class Base {
    template <class U> friend class Foo;
protected:
    T container;
};

The forward declaration of Foo is sometimes not needed, but I think it makes things clearer, and it can avoid gotchas when things start getting more complicated with namespaces, nested classes, etc.

0
On

Only Base can say Foo is its friend.

template<typename T> friend class Foo; // every Foo<T> is a friend of Base