Вступление
В базовом программировании на C ++ тип данных e.грамм., int или char, должны быть указаны в объявлении или определении. Такое значение, как 4, 22 или -5, является целым числом. Значение, такое как 'A', 'b' или 'c', является символом. Механизм шаблонов позволяет программисту использовать универсальный тип для набора фактических типов. Например, программист может решить использовать идентификатор T для int или char. Алгоритм C ++ может иметь более одного универсального типа. С, скажем, T для int или char, U может обозначать тип с плавающей запятой или указатель. Класс, такой как строковый или векторный класс, подобен типу данных, а созданные экземпляры объектов подобны значениям типа данных, который является указанным классом. Таким образом, механизм шаблонов также позволяет программисту использовать идентификатор универсального типа для набора классов.
Шаблон C ++ создает алгоритм, не зависящий от типа используемых данных. Таким образом, один и тот же алгоритм с множеством экземпляров одного и того же типа может использовать разные типы при разных исполнениях. Сущности переменной, функции, структуры и класса могут иметь шаблоны. В этой статье объясняется, как объявлять шаблоны, как определять шаблоны и как их применять в C++. Вы уже должны знать вышеупомянутые сущности, чтобы понимать темы, затронутые в этой статье.
Типы
Скалярный
Скалярные типы: void, bool, char, int, float и pointer.
Классы как типы
Конкретный класс можно рассматривать как тип, а его объекты - как возможные значения.
Универсальный тип представляет собой набор скалярных типов. Список скалярных типов обширен. Например, тип int имеет другие связанные типы, такие как short int, long int и т. Д. Универсальный тип также может представлять набор классов.
Переменная
Пример объявления и определения шаблона следующий:
шаблонТ пи = 3.14;
Прежде чем продолжить, обратите внимание, что этот вид операторов не может появляться в функции main () или в любой области блока. Первая строка - это объявление заголовка шаблона с выбранным программистом универсальным именем типа, T. Следующая строка - это определение идентификатора pi, который относится к универсальному типу T. Точность того, является ли T int или float или каким-либо другим типом, может быть достигнута в функции C ++ main () (или какой-либо другой функции). Такая точность будет сделана с переменной pi, а не T.
Первая строка - это объявление заголовка шаблона. Это объявление начинается с зарезервированного слова, шаблона, а затем с открытой и закрытой угловых скобок. В угловых скобках указан как минимум один идентификатор универсального типа, например T, указанный выше. Может быть несколько идентификаторов универсального типа, каждому из которых предшествует зарезервированное слово typename. Такие универсальные типы в этой позиции называются параметрами шаблона.
Следующий оператор может быть записан в main () или в любой другой функции:
cout << piИ функция отобразит 3.14. Выражение пи
При специализации выбранный тип данных, например float, помещается в угловые скобки после переменной. Если в объявлении заголовка шаблона есть более одного параметра шаблона, в выражении специализации будет соответствующее количество типов данных в том же порядке.
В специализации тип известен как аргумент шаблона. Не путайте это с аргументом функции для вызова функции.
Тип по умолчанию
Если в специализации не указан тип, предполагается тип по умолчанию. Итак, из следующего выражения:
шаблонU pi = "любовь";
отображение из:
cout << pi<> << '\n';
«любовь» к постоянному указателю на char. Обратите внимание в объявлении, что U = const char *. Угловые скобки будут пустыми при специализации (тип не указан); фактический тип считается константным указателем на char, тип по умолчанию. Если бы при специализации требовался какой-то другой тип, то имя типа записывалось бы в угловых скобках. Если для специализации требуется тип по умолчанию, повторение типа в угловых скобках необязательно, i.е., угловые скобки можно оставить пустыми.
Примечание: тип по умолчанию все еще можно изменить при специализации, установив другой тип.
структура
В следующем примере показано, как параметр шаблона можно использовать со структурой:
шаблонТ Джон = 11;
Т Петр = 12;
Т Мэри = 13;
Т Радость = 14;
;
Это возраст учащихся класса (класса). Первая строка - это объявление шаблона. Тело в фигурных скобках - это фактическое определение шаблона. Возраст можно вывести в функции main () следующим образом:
Возрастcout << grade7.John << " << grade7.Mary << '\n';
Результат: 11 13. Первый оператор здесь выполняет специализацию. Обратите внимание, как это было сделано. Он также дает имя для объекта структуры: grade7. Второй оператор имеет обычные выражения объекта структуры. Структура похожа на класс. Здесь Ages похож на имя класса, а grade7 - это объект класса (структура).
Если некоторые значения возраста являются целыми числами, а другие - числами с плавающей запятой, то структуре требуются два общих параметра, как показано ниже:
шаблонТ Джон = 11;
U Питер = 12.3;
Т Мэри = 13;
U радость = 14.6;
;
Соответствующий код для функции main () выглядит следующим образом:
Возрастcout << grade7.John << " << grade7.Peter << '\n';
Результат: 11 12.3. При специализации порядок типов (аргументов) должен соответствовать порядку универсальных типов в объявлении.
Объявление шаблона можно отделить от определения следующим образом:
шаблонТ Джон;
У Питера;
Т Мэри;
U Joy;
;
Возраст
Первый сегмент кода - это просто объявление шаблона (нет присваиваний). Второй сегмент кода, который является просто оператором, является определением идентификатора grade7. Слева - объявление идентификатора grade7. Справа находится список инициализаторов, который присваивает соответствующие значения элементам структуры. Второй сегмент (оператор) можно записать в функцию main (), в то время как первый сегмент остается вне функции main ().
Не тип
Примеры типов, не относящихся к данным, включают int, указатель на объект, указатель на функцию и типы auto. Есть и другие нетипы, которые в этой статье не рассматриваются. Нетип подобен неполному типу, значение которого дается позже и не может быть изменено. В качестве параметра он начинается с определенного не-типа, за которым следует идентификатор. Значение идентификатора дается позже, при специализации, и не может быть изменено снова (как константа, значение которой дается позже). Следующая программа иллюстрирует это:
#включатьиспользуя пространство имен std;
шаблон
Т Джон = N;
U Питер = 12.3;
Т Мэри = N;
U радость = 14.6;
;
int main ()
Возраст
cout << grade7.John << " << grade7.Joy << '\n';
возврат 0;
При специализации первый тип, int, в угловых скобках больше для формальности, чтобы убедиться, что количество и порядок параметров соответствуют количеству и порядку типов (аргументов). Значение N было присвоено при специализации. Результат: 11 14.6.
Частичная специализация
Предположим, что в шаблоне есть четыре универсальных типа и что среди четырех типов необходимы два типа по умолчанию. Это может быть достигнуто с помощью конструкции частичной специализации, в которой не используется оператор присваивания. Итак, конструкция частичной специализации дает значения по умолчанию для подмножества универсальных типов. Однако в схеме частичной специализации необходимы базовый класс (структура) и класс частичной специализации (структура). Следующая программа иллюстрирует это для одного универсального типа из двух универсальных типов:
#включатьиспользуя пространство имен std;
// базовый шаблонный класс
шаблон
структура возрастов
;
// частичная специализация
шаблон
структура возрастов
Т1 Джон = 11;
float Peter = 12.3;
Т1 Мэри = 13;
плавать Радость = 14.6;
;
int main ()
Возраст
cout << grade7.John << " << grade7.Joy << '\n';
возврат 0;
Определите объявление базового класса и определение его частичного класса. Объявление базового класса в заголовке шаблона имеет все необходимые общие параметры. Объявление заголовка шаблона класса частичной специализации имеет только общий тип. В схеме используется дополнительный набор угловых скобок, который идет сразу после имени класса в определении частичной специализации. Это то, что на самом деле делает частичную специализацию. Он имеет тип по умолчанию и тип, отличный от типа по умолчанию, в порядке, записанном в базовом классе. Обратите внимание, что типу по умолчанию по-прежнему можно присвоить другой тип в функции main ().
Соответствующий код в функции main () может быть следующим:
Возрастcout << grade7.John << " << grade7.Joy << '\n';
Результат: 11 14.6.
Пакет параметров шаблона
Пакет параметров - это параметр шаблона, который принимает ноль или более универсальных типов шаблона для соответствующих типов данных. Параметр пакета параметров начинается с зарезервированного слова typename или class. Далее следуют три точки, а затем идентификатор упаковки. Следующая программа показывает, как пакет параметров шаблона может использоваться со структурой:
#включатьиспользуя пространство имен std;
шаблон
int John = 11;
float Peter = 12.3;
int Mary = 13;
плавать Радость = 14.6;
;
int main ()
Возраст
cout << gradeB.John << " << gradeB.Mary << '\n';
Возраст
cout << gradeC.Peter << " << gradeC.Joy << '\n';
Возраст
cout << gradeD.John << " << gradeD.Joy << '\n';
Возраст <> gradeA; // как по умолчанию
cout << gradeA.John << " << gradeA.Joy << '\n';
возврат 0;
Результат:
11 1312.3 14.6
11 14.6
11 14.6
Шаблоны функций
Упомянутые выше функции шаблона применяются аналогично шаблонам функций. В следующей программе показана функция с двумя общими параметрами шаблона и тремя аргументами:
#включатьиспользуя пространство имен std;
шаблон
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';
int main ()
func (12, '$', «500»);
возврат 0;
Результат выглядит следующим образом:
В магазине 12 книг стоимостью 500 долларов.
Отделение от прототипа
Определение функции можно отделить от ее прототипа, как показано в следующей программе:
#включатьиспользуя пространство имен std;
шаблон
шаблон
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';
int main ()
func (12, '$', «500»);
возврат 0;
Примечание: объявление шаблона функции не может появляться в функции main () или в любой другой функции.
Перегрузка
Перегрузка одной и той же функции может происходить с разными объявлениями заголовка шаблона. Следующая программа иллюстрирует это:
#включатьиспользуя пространство имен std;
шаблон
cout << "There are " << no << " books worth " << cha << str << " in the store." << '\n';
шаблон
cout << "There are " << no << " books worth $" << str << " in the store." << '\n';
int main ()
func (12, '$', «500»);
func (12, «500»);
возврат 0;
Результат:
В магазине 12 книг стоимостью 500 долларов.
В магазине 12 книг стоимостью 500 долларов.
Шаблоны классов
Функции упомянутых выше шаблонов применяются аналогично шаблонам классов. Следующая программа представляет собой объявление, определение и использование простого класса:
#включатьиспользуя пространство имен std;
класс TheCla
общественность:
int num;
static char ch;
void func (char cha, const char * str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
статическая пустота весело (char ch)
если (ch == 'a')
cout << "Official static member function" << '\n';
;
int main ()
TheCla obj;
объект.число = 12;
объект.func ('$', «500»);
возврат 0;
Результат выглядит следующим образом:
В магазине 12 книг стоимостью 500 долларов.
Следующая программа представляет собой указанную выше программу с объявлением заголовка шаблона:
#включатьиспользуя пространство имен std;
шаблон
общественность:
T num;
статический U ч;
void func (U cha, const char * str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
статическая пустота веселье (U ch)
если (ch == 'a')
cout << "Official static member function" << '\n';
;
int main ()
TheCla
объект.число = 12;
объект.func ('$', «500»);
возврат 0;
Вместо слова typename в списке параметров шаблона можно использовать слово class. Обратите внимание на специализацию в объявлении объекта. Результат все тот же:
В магазине 12 книг стоимостью 500 долларов.
Разделительная декларация
Объявление шаблона класса можно отделить от кода класса следующим образом:
шаблоншаблон
общественность:
T num;
статический U ч;
void func (U cha, const char * str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
статическая пустота веселье (U ch)
если (ch == 'a')
cout << "Official static member function" << '\n';
;
Работа со статическими членами
В следующей программе показано, как получить доступ к статическому члену данных и статической функции-члену:
#включатьиспользуя пространство имен std;
шаблон
общественность:
T num;
статический U ч;
void func (U cha, const char * str)
cout << "There are " << num << " books worth " << cha << str << " in the store." << '\n';
статическая пустота веселье (у ча)
если (ch == 'a')
cout << "Official static member function" << cha << '\n';
;
шаблон
int main ()
TheCla
возврат 0;
Присвоение значения статическому элементу данных является объявлением и не может быть в main (). Обратите внимание на использование и расположение универсальных типов и универсального типа данных в операторе присваивания. Кроме того, обратите внимание, что функция-член статических данных была вызвана в main () с фактическими типами данных шаблона. Результат следующий:
Официальная статическая функция-член.
Компиляция
Объявление (заголовок) и определение шаблона должны быть в одном файле. То есть они должны быть в одной единице перевода.
Заключение
Шаблоны C ++ делают алгоритм независимым от типа используемых данных. Сущности переменной, функции, структуры и класса могут иметь шаблоны, которые включают объявление и определение. Создание шаблона также включает в себя специализацию, когда универсальный тип принимает фактический тип. Объявление и определение шаблона должны быть в одной единице перевода.