Сделайте все производные шаблоны класса другом другого класса в C ++ - PullRequest
0 голосов
/ 15 декабря 2018

Допустим, мне нужна следующая иерархия:

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 */
    }
};

Теперь я хочу независимый класс (не производный от Base), который может обращаться к Base<T>::container напрямую из Base или любого производного класса.Я прочитал о шаблонных классах друзей , и, похоже, это решение моей проблемы, но я пока не мог понять синтаксис.Я ищу что-то вроде:

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()

строка класса друга вызывает error: specialization of ‘template<class T> class Base’ must appear at namespace scope template<T> friend class Base<T>, а переменная-член container по-прежнему недоступна.

Ответы [ 2 ]

0 голосов
/ 15 декабря 2018

Только Base может сказать Foo его друг.

template<typename T> friend class Foo; // every Foo<T> is a friend of Base
0 голосов
/ 15 декабря 2018

Пара вопросов:

Так же, как вы не ставите <T> после имени класса при определении шаблона класса:

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

, вы не должны ставить егопосле имени класса при объявлении шаблона класса, будь то в предварительном объявлении или объявлении друга:

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

(Если вы не создаете частичную специализацию шаблона класса. Например, если шаблон класса Xуже объявлено, тогда template <class T> class X<T*> { ... }; определяет частичную специализацию, которая будет использоваться вместо основного шаблона, когда аргумент шаблона является указателем.)

И у вас есть объявление друга в обратном направлении: оно должно появиться внутри классас непубличным членом (членами), и назовите другой класс (ы), которым разрешено использовать члены.(Если бы это работало наоборот, то любой новый класс мог бы получить доступ к закрытым и защищенным членам любого другого класса без разрешения класса-владельца!)

Поэтому вам потребуется:

template <class T> class Foo;

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

Предварительное объявление Foo иногда не требуется, но я думаю, что оно делает вещи более понятными, и оно может избежать ошибок, когда вещи становятся более сложными с пространствами имен, вложенными классами и т. Д.

...