Объявления друзей в шаблонах классов
· обычный (не шаблонный) дружественный класс или дружественная функция. В следующем примере функция foo(), функция-член bar() и класс foobar
объявлены друзьями всех конкретизаций шаблона QueueItem:
class Foo { void bar(); }; template <class T> class QueueItem { friend class foobar; friend void foo(); friend void Foo::bar(); // ... |
};
Ни класс foobar, ни функцию foo() не обязательно объявлять или определять в глобальной области видимости перед объявлением их друзьями шаблона QueueItem.
Однако перед тем как объявить другом какой-либо из членов класса Foo, необходимо определить его. Напомним, что член класса может быть введен в область видимости только через определение объемлющего класса. QueueItem не может ссылаться на Foo::bar(), пока не будет найдено определение Foo;
· связанный
дружественный шаблон класса или функции. В следующем примере определено взаимно однозначное соответствие между классами, конкретизированными по шаблону QueueItem, и их друзьями – также конкретизациями шаблонов. Для каждого класса, конкретизированного по шаблону QueueItem, ассоциированные конкретизации foobar, foo() и Queue::bar()
являются друзьями.
template <class Type> class foobar { ... }; template <class Type> void foo( QueueItem<Type> ); template <class Type> class Queue { void bar(); // ... }; template <class Type> class QueueItem { friend class foobar<Type>; friend void foo<Type>( QueueItem<Type> ); friend void Queue<Type>::bar(); // ... |
};
Прежде чем шаблон класса можно будет использовать в объявлениях друзей, он сам должен быть объявлен или определен. В нашем примере шаблоны классов foobar и Queue, а также шаблон функции foo()
следует объявить до того, как они объявлены друзьями в QueueItem.
Синтаксис, использованный для объявления foo() другом, может показаться странным:
friend void foo<Type>( QueueItem<Type> );
За именем функции следует список явных аргументов шаблона: foo<Type>. Такой синтаксис показывает, что в качестве друга объявляется конкретизированный шаблон функции foo(). Если бы список явных аргументов был опущен:
friend void foo( QueueItem<Type> );
то компилятор интерпретировал бы объявление как относящееся к обычной функции (а не к шаблону), у которой тип параметра – это экземпляр шаблона QueueItem. Как отмечалось в разделе 10.6, шаблон функции и одноименная обычная функция могут сосуществовать, и присутствие объявления такого шаблона перед определением класса QueueItem не вынуждает компилятор соотнести объявление друга именно с ним. Для того, чтобы соотнесение было верным, в конкретизированном шаблоне функции необходимо указать список явных аргументов;
· несвязанный
дружественный шаблон класса или функции. В следующем примере имеется отображение один-ко-многим между конкретизациями шаблона класса QueueItem и его друзьями. Для каждой конкретизации типа QueueItem все конкретизации foobar, foo() и Queue<T>::bar()
являются друзьями:
template <class Type> class QueueItem { template <class T> friend class foobar; template <class T> friend void foo( QueueItem<T> ); template <class T> friend class Queue<T>::bar(); // ... |
Следует отметить, что этот вид объявлений друзей в шаблоне класса не поддерживается компиляторами, написанными до принятия стандарта C++.