Язык программирования C++. Вводный курс

Объявления друзей в шаблонах классов


·                  обычный (не шаблонный) дружественный класс или дружественная функция. В следующем примере функция 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++.


Содержание раздела