Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Параметры и аргументы шаблонов

Поиск

Одним из важных вопросов в работе с шаблонами классов является механизм параметров и аргументов. Мы уже кратко затрагивали этот вопрос, теперь же рассмотрим параметры и аргументы шаблонов подробно.

Параметры шаблона классов служат для обозначения общих свойств классов, объединяемых данным шаблоном. Они могут обозначать типы, классы, переменные и константы, которые могут быть подставлены в точку инстанцирования шаблона. Аргументы шаблона непосредственно представляют типы, классы, переменные и константы, подставляемые в точках инстанцирования, реализации и специализации шаблонов вместо соответствующих параметров.[20] Напомним, что шаблон должен включать хотя бы один параметр. Максимальное количество параметров шаблона при этом не ограничивается.

Шаблонный класс может иметь три вида параметров. Наиболее распространены среди них параметры-типы (type-parameters). Параметры этого вида обозначают обобщенные типы (мы уже видели их применение выше в шаблоне CVector). Их можно использовать внутри определения шаблона для задания типов локальных переменных и функций, типов параметров функций и т.д. Другой вид параметров шаблона – шаблонные параметры (template parameters). Их назначение состоит в обобщении других параметров (например, с их помощью можно переписать шаблон CVector так, что он сможет хранить свои элементы в любом контейнере, а не только в одномерном динамическом массиве). Третий вид параметров шаблонов – ординарные параметры[21]. Эти параметры задаются как обычные параметры функций (декларации) путем указания идентификатора некоторого типа (встроенного или определенного пользователем) и неквалифицированного имени параметра. Одна из целей использования ординарных параметров – введение ограничений (например, с их помощью вместо шаблона, представляющего векторы «вообще», можно ввести шаблон, моделирующий векторы заданной длины).

Рассмотрим синтаксис параметров шаблонов.

Параметры-типы записываются в одном из следующих форматов:

Class identifier

Typename identifier

где identifier – это имя параметра. Смысловых различий при использовании служебных слов class и typename нет. Для записи шаблонных параметров шаблонов применяется такой формат:

template <template_parameter_list> class identifier

где template_parameter_list отображает список параметров самого шаблонного параметра, а identifier представляет имя параметра. Наконец, ординарные параметры используют формат обычной декларации параметра функции:

Cv-modifiers type identifier

где type – стандартный или пользовательский тип, cv-modifiers – модификаторы (например, const), identifier – имя параметра.

Для иллюстрации ниже дан набросок определения шаблона классов, моделирующего понятие «бинарное отображение», где используются различные виды параметров:

template <class Key, class Data, int Len,

template <class T, int L> class Container>

// Key, Data – параметры-типы (типы ключа и данных отображения)

// Len – ординарный параметр (ограничение на длину контейнера)

// Container – контейнер, где содержится информация отображения

class СMap {

Container <Key, Len> __key;

Container <Data, Len> __data;

...

};

Параметры шаблонных классов всех трех видов могут иметь значения по умолчанию. Их роль такая же, как и у функций: если аргумент отсутствует, то вместо него подставляется соответствующее умалчиваемое значение. Однако это значение используется при инстанцировании классов из шаблона. Для задания значения по умолчанию используется символ =, за которым следует выражение. Задать такое значение можно либо в декларации, либо в определении шаблона (и там, и там одновременно его задание запрещено и рассматривается как переопределение умалчиваемого значения). Для параметров-типов значением по умолчанию может быть идентификатор типа. Формат записи параметра-типа с учетом этого значения таков (отметим, что identifier может отсутствовать):

class identifier = type-id

typename identifier = type-id

Для шаблонных параметров значение по умолчанию – это выражение-идентификатор (id-expression). Формат записи шаблонного параметра с учетом значения по умолчанию будет таким:

template <template_parameter_list> class identifier = id-expression

Для ординарных параметров формат с умалчиваемым значением такой же, как и у функций.

Если некоторый параметр шаблона имеет умалчиваемое значение, то и все параметры, следующие за ним, независимо от их вида также должны иметь умалчиваемые значения. Сфера действия умалчиваемого значения распространяется от точки его появления до конца определения шаблона. Таким образом, его можно использовать при задании следующих по тексту параметров шаблона.

В примере, который дан ниже, иллюстрируются различные варианты задания значений по умолчанию для параметров разных видов и приводятся варианты инстанцирования.

Пример

template <class T> class CSomeClass { /*... */ };

template <class U> class CAnotherClass { /*... */ };

...

template <class C1 = int, class C2 = C1,

template <class T> class F = CSomeClass, C2 p = 0>

Class MyTemplate

{ /*... */ };

...

MyTemplate<short,unsigned,CAnotherClass,11> v;

// инстанцируется класс MyTemplate<short,unsigned,CAnotherClass<U>,unsigned=11>

...

MyTemplate<short,unsigned,CAnotherClass> vv;

// инстанцируется класс MyTemplate<short,unsigned,CAnotherClass<U>,unsigned=0>

...

MyTemplate<short,int> vvv;

// инстанцируется класс MyTemplate<short,int,CSomeClass<T>,int=0>

...

MyTemplate<unsigned> vvvv;

// инстанцируется класс MyTemplate<unsigned,unsigned,CSomeClass<T>,unsigned=0>

...

MyTemplate<> vvvvv;

// инстанцируется класс MyTemplate<int,int,CSomeClass<T>,int=0>

Каждому виду параметров шаблона соответствует свой набор аргументов (это, в частности, уже должно быть ясно из приведенного примера и всего изложения). Аргументы тоже делятся на аргументы-типы, шаблонные аргументы и ординарные аргументы.

Аргумент-тип представляет собой идентификатор стандартного или определенного пользователем типа. Этот тип не может быть локальным. Он должен иметь какой-либо из типов компоновки. Наконец, он должен иметь имя.

Шаблонный аргумент – это имя ранее определенного шаблонного класса. Специализации шаблонов в качестве таких аргументов не допускаются.

Ординарный аргумент – это имя или выражение, подставляемое вместо ординарного параметра.

Ординарный параметр может иметь интегральный или перечислимый тип (возможно, с модификаторами), быть ссылкой или указателем на объект или функцию, а также быть указателем на компонент. Если ординарный параметр не является ссылкой, то он представляет собой праводопустимое выражение (соответственно, нельзя получить его адрес, ему нельзя присвоить значение и т.д.). Ординарный параметр не может иметь тип void, он также не может быть вещественным (но может быть указателем или ссылкой на вещественный тип) и не может быть классом.

Ординарный аргумент может представлять собой константное выражение интегрального или перечислимого типа, имя ординарного параметра, имя объекта или функции с внешним типом компоновки (включая шаблоны функций), адрес объекта, функции или шаблона функций с внешним типом компоновки, а также указатель на компонент. Он не может быть ни строковым литералом, ни адресом элемента массива, ни адресом или именем нестатического компонента класса. Также недопустимым ординарным аргументом будет леводопустимое выражение без внешней компоновки. При необходимости выполняются автоматические преобразования типов ординарных аргументов (например, расширение интегральных типов[22], преобразование вида «массив–указатель» и др.).

Ниже приводится пример, иллюстрирующий использование различных аргументов шаблонов и перечисленные ограничения.

Пример

template <const int & cnref> struct Template1 { /*... */ };

...

Template1<100> object1; // ошибка, привязка ссылки к временному объекту

int nvar = 100;

Template1<nvar> object2; // нормально

...

template <int * pn> class Template2 { /*... */ };

int array[10];

struct Structure { int m; static int sm; } str;

...

Template2<&array[0]> object3; // ошибка, адрес элемента массива

Template2<&str.m> object4; // ошибка, адрес нестатического компонента

Template2<&Structure::sm> object5; // нормально, адрес статического компонента

...

template <class T, char * psz> class Template3 { /*... */ };

...

Template3<int,”token”> object6; // ошибка, строковый литерал

char psz[] = “another token”;

Template3<int,psz> object7; // нормально




Поделиться:


Последнее изменение этой страницы: 2016-08-14; просмотров: 160; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.17.183.186 (0.007 с.)