Сделайте все производные шаблоны класса другом другого класса в C++
Допустим, мне нужна следующая иерархия:
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 ответа
Пара вопросов:
Так же, как вы не ставите <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
иногда не требуется, но я думаю, что это делает вещи более понятными, и это может избежать ошибок, когда все становится более сложным с пространствами имен, вложенными классами и т. д.
Только Base
можно сказать Foo
это его друг.
template<typename T> friend class Foo; // every Foo<T> is a friend of Base