16.7. Шаблоны-члены
16.7. Шаблоны-члены
Шаблон функции или класса может быть членом обычного класса или шаблона класса. Определение шаблона-члена похоже на определение шаблона: ему предшествует ключевое слово template, за которым идет список параметров:
template class T
class Queue {
private:
// шаблон класса-члена
template class Type class CL
{
Type member;
T mem;
};
// ...
public:
// шаблон функции-члена
template class Iter
void assign( Iter first, Iter last )
{
while ( ! is_empty() )
remove(); // вызывается Queue T ::remove()
for ( ; first != last; ++first )
add( *first ); // вызывается Queue T ::add( const T & )
}
}
(Отметим, что шаблоны-члены не поддерживаются компиляторами, написанными до принятия стандарта C++. Эта возможность была добавлена в язык для поддержки реализации абстрактных контейнерных типов, представленных в главе 6.)
Объявление шаблона-члена имеет собственные параметры. Например, у шаблона класса CL есть параметр Type, а у шаблона функции assign() - параметр Iter. Помимо этого, в определении шаблона-члена могут использоваться параметры объемлющего шаблона класса. Например, у шаблона CL есть член типа T, представляющего параметр включающего шаблона Queue.
Объявление шаблона-члена в шаблоне класса Queue означает, что конкретизация Queue потенциально может содержать бесконечное число различных вложенных классов CL функций-членов assign(). Так, конкретизированный экземпляр Queue включает вложенные типы:
Queueint::CLchar
Queueint ::CLstring
и вложенные функции:
void Queueint ::assign( int *, int * )
void Queueint ::assign( vectorint ::iterator,
vectorint ::iterator )
Для шаблона-члена действуют те же правила доступа, что и для других членов класса. Так как шаблон CL является закрытым членом шаблона Queue, то лишь функции-члены и друзья Queue могут ссылаться на его конкретизации. С другой стороны, шаблон функции assign() объявлен открытым членом и, значит, доступен во всей программе.
Шаблон-член конкретизируется при его использовании в программе. Например, assign() конкретизируется в момент обращения к ней из main():
int main()
{
// конкретизация Queueint
Queueint qi;
// конкретизация Queueint::assign( int *, int * )
int ai[4] = { 0, 3, 6, 9 };
qi.assign( ai, ai + 4 );
// конкретизация Queueint ::assign( vectorint ::iterator,
// vectorint ::iterator )
vectorint vi( ai, ai + 4 );
qi.assign( vi.begin(), vi.end() );
}
Шаблон функции assign(), являющийся членом шаблона класса Queue, иллюстрирует необходимость применения шаблонов-членов для поддержки контейнерных типов. Предположим, имеется очередь типа Queueint, в которую нужно поместить содержимое любого другого контейнера (списка, вектора или обычного массива), причем его элементы имеют либо тип int (т.е. тот же, что у элементов очереди), либо приводимый к типу int. Шаблон-член assign()позволяет это сделать. Поскольку может быть использован любой контейнерный тип, то интерфейс assign() программируется в расчете на употребление итераторов; в результате реализация оказывается не зависящей от фактического типа, на который итераторы указывают.
В функции main() шаблон-член assign() сначала конкретизируется типом int*, что позволяет поместить в qi содержимое массива элементов типа int. Затем шаблон-член конкретизируется типом vectorint::iterator - это дает возможность поместить в очередь qi содержимое вектора элементов типа int. Контейнер, содержимое которого помещается в очередь, не обязательно должен состоять из элементов типа int. Разрешен любой тип, который приводится к int. Чтобы понять, почему это так, еще раз посмотрим на определение assign():
template class Iter
void assign( Iter first, Iter last )
{
// удалить все элементы из очереди
for ( ; first != last; ++first )
add( *first );
}
Вызываемая из assign() функция add() - это функция-член QueueType::add(). Если Queue конкретизируется типом int, то у add() будет следующий прототип:
void Queueint::add( const int &val );
Аргумент *first должен иметь тип int либо тип, которым можно инициализировать параметр-ссылку на const int. Преобразования типов допустимы. Например, если воспользоваться классом SmallInt из раздела 15.9, то содержимое контейнера, в котором хранятся элементы типа SmallInt, с помощью шаблона-члена assign() помещается в очередь типа Queueint. Это возможно потому, что в классе SmallInt имеется конвертер для приведения SmallInt к int:
class SmallInt {
public:
SmallInt( int ival = 0 ) : value( ival ) { }
// конвертер: SmallInt == int
operator int() { return value; }
// ...
private:
int value;
};
int main()
{
// конкретизация Queueint
Queueint qi;
vectorSmallInt vsi;
// заполнить вектор
// конкретизация
// Queueint ::assign( vectorSmallInt ::iterator,
// vectorSmallInt ::iterator )
qi.assign( vsi.begin(), vsi.end() );
listint* lpi;
// заполнить список
// ошибка при конкретизации шаблона-члена assign():
// нет преобразования из int* в int
qi.assign( lpi.begin(), lpi.end() );
}
Первая конкретизация assign() правильна, так как существует неявное преобразование из типа SmallInt в тип int и, следовательно, обращение к add() корректно. Вторая же конкретизация ошибочна: объект типа int* не может инициализировать ссылку на тип const int, поэтому вызвать функцию add() невозможно.
Для контейнерных типов из стандартной библиотеки C++ имеется функция assign(), которая ведет себя так же, как функция-шаблон assign() для нашего класса Queue.
Любую функцию-член можно задать в виде шаблона. Это относится, в частности, к конструктору. Например, для шаблона класса Queue его можно определить следующим образом:
template class T
class Queue {
// ...
public:
// шаблон-член конструктора
template class Iter
Queue( Iter first, Iter last )
: front( 0 ), back( 0 )
{
for ( ; first != last; ++first )
add( * first );
}
};
Такой конструктор позволяет инициализировать очередь содержимым другого контейнера. У контейнерных типов из стандартной библиотеки C++ также есть предназначенные для этой цели конструкторы в виде шаблонов-членов. Кстати, в первом (в данном разделе) определении функции main() использовался конструктор-шаблон для вектора:
vector int vi( ai, ai + 4 );
Это определение конкретизирует шаблон конструктора для контейнера vector типом int*, что позволяет инициализировать вектор содержимым массива элементов типа int.
Шаблон-член, как и обычные члены, может быть определен вне определения объемлющего класса или шаблона класса. Так, являющиеся членами шаблон класса CL или шаблон функции assign() могут быть следующим образом определены вне шаблона Queue:
template class T
class Queue {
private:
template class Type class CL;
// ...
public:
template class Iter
void assign( Iter first, Iter last );
// ...
};
template class T template class Type
class Queue T ::CLType
{
Type member;
T mem;
};
template class T template class Iter
void Queue T ::assign( Iter first, Iter last )
{
while ( ! is_empty() )
remove();
for ( ; first != last; ++first )
add( *first );
}
Определению шаблона-члена, которое находится вне определения объемлющего шаблона класса, предшествует список параметров объемлющего шаблона класса, а за ним должен следовать собственный такой список. Вот почему определение шаблона функции assign() (члена шаблона класса Queue) начинается с
template class T template class Iter
Первый список параметров шаблона template class T относится к шаблону класса Queue. Второй - к самому шаблону-члену assign(). Имена параметров не обязаны совпадать с теми, которые указаны внутри определения объемлющего шаблона класса. Приведенная инструкция по-прежнему определяет шаблон-член assign():
template class TT template class IterType
void Queue TT ::assign( IterType first, IterType last )
{ ... }
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Шаблоны
Шаблоны Делать работу, которая до этого уже была выполнена другими, – напрасная трата времени и сил. Ваши усилия, затраченные на оформление списка приглашенных на вечеринку, можно направить на другие неотложные дела, если воспользоваться подсистемой шаблонов. Созданные
Шаблоны и обобщенность
Шаблоны и обобщенность Место для вашей цитаты. — Бьярн Страуструп (Bjarne Stroustrup), [Stroustrup00] §13 Аналогично: место для вашего введения.В этом разделе мы считаем наиболее значимой рекомендацию 64 — "Разумно сочетайте статический и динамический
4.7. Стили и шаблоны
4.7. Стили и шаблоны Как вы, наверное, уже успели убедиться на своем опыте, процесс форматирования занимает достаточно много времени. Если вы хотите, чтобы ваш курсовой проект или бизнес,план было приятно читать, придется приложить немало усилий. Упростить процедуру
Шаблоны
Шаблоны Программа Excel предлагает множество готовых шаблонов оформления документа. Вы можете выбрать готовый шаблон, а затем просто подставить в ячейки свои данные. С помощью шаблонов быстро подготавливают, например, такие документы, как бланки, ведомости, календари,
15.1.1. Члены и не члены класса
15.1.1. Члены и не члены класса Рассмотрим операторы равенства в нашем классе String более внимательно. Первый оператор позволяет устанавливать равенство двух объектов, а второй – объекта и C-строки:#include "String.h"int main() {String flower;// что-нибудь записать в переменную flowerif ( flower == "lily" ) //
16. Шаблоны классов
16. Шаблоны классов В этой главе описывается, как определять и использовать шаблоны классов. Шаблон - это предписание для создания класса, в котором один или несколько типов либо значений параметризованы. Начинающий программист может использовать шаблоны, не понимая
Синтаксические шаблоны
Синтаксические шаблоны Некоторые фрагменты кода представляют синтаксические шаблоны (syntax patterns), то есть модели кода, которые демонстрируют обязательные и необязательные элементы синтаксиса операторов SQL или команд командной строки.Для синтаксических шаблонов
Шаблоны
Шаблоны Языки программирования С и Си++ обеспечивают строгую проверку типов данных. Некоторые языки не обеспечивают такой проверки и она полностью ложится на плечи программиста. Например в языке PL1 вы можете сравнивать значение строковой и числовой переменных. Это не
Шаблоны в MFC
Шаблоны в MFC В библиотеке классов MFC определен ряд шаблонов для создания таких структур хранения информации как массив, список, словарь. Более подробно об этих шаблонах вы можете прочитать в разделе “Коллекции” главы “Некоторые классы
Именованные шаблоны
Именованные шаблоны Вместо того чтобы при помощи атрибута match указывать, какая часть входящего документа должна преобразовываться данным шаблоном, ему можно присвоить имя и вызывать в любой момент вне зависимости от контекста преобразования. Такие шаблоны очень схожи
Встроенные шаблоны
Встроенные шаблоны Для того чтобы обеспечить рекурсивную обработку документа при преобразовании, в XSLT существуют так называемые встроенные шаблоны. Несмотря на то, что они не описываются в преобразованиях явным образом, встроенные шаблоны применяются процессорами по
13.2.2. Шаблоны
13.2.2. Шаблоны Вы хотите создать стандартный документ, например резюме, служебную записку, отчет? Тогда вам пригодятся стандартные шаблоны MS Word. Выполните команду Файл, Создать. В правой части окна Word появится окошко Создание документа, в котором можно выбрать один из
Шаблоны
Шаблоны Шаблон – это своего рода набросок, который можно изменить под конкретные нужды. Очень часто вам придется писать однотипные сообщения вроде «Привет. Как дела?» или «Я сегодня занят. Когда освобожусь – перезвоню!». Вы можете облегчить себе жизнь, записав подобные
Шаблоны
Шаблоны Если вам часто приходится создавать документы одного типа, вы можете значительно повысить эффективность работы с помощью шаблонов. Шаблон – это заготовка нового документа, содержащая текст, рисунки, стили и другие элементы.Чтобы познакомиться с возможностями
Шаблоны
Шаблоны Шаблон представляет собой заготовку или бланк для часто используемых документов. Можно воспользоваться готовым шаблоном, загрузить шаблон из Интернета или использовать в качестве шаблона любую ранее сохраненную книгу.Для создания нового документа на основе