Как сделать функцию шаблонной c

Добавил пользователь Валентин П.
Обновлено: 18.09.2024

Начинающим программистам очень часто непонятны шаблоны. Шаблоны для новичков в большинстве случаев как тёмный лес. В некоторых книгах о шаблонах написано очень мудрёно, в некоторых попроще. Попытаемся понять, что такое шаблоны функций.

T MyFunc ( T a ) //Тип функции MyFunc определяется шаблоном. В функцию принимается один параметр a, тип которого также определяется шаблоном

  • Шаблоны функций — они действуют подобно универсальной перегрузке функций.

Конечно, шаблоны функций не являются на 100% универсальным способом перегрузки, но основной принцип работы шаблонов очень сильно похож именно на универсальную перегрузку функций. Вместо того, чтобы писать много функций, описывая каждую для конкретного случая, можно написать одну функцию, для которой описать общий вид, и использовать для этой функции вызовы с явным указанием типов. Т. е. настоящие типы описывать не в описании функции, а в месте вызова функции. Это называется обобщённым программированием. Для того, чтобы это работало — используют шаблоны функций.

  • Ключевое слово template обозначает шаблон.
  • template обозначает Шаблон функции с одним параметром T.
  • Внутри угловых скобок шаблона функции описываются параметры шаблона.

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

Имена параметров чаще всего называют Т1, Т2, Т3 и т. д., это из-за того, что шаблонный параметр — это тип: Тип1, Тип2, Тип3…

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

После написания template и указания в угловых скобках всех параметров (В приведенном примере только один параметр: T ) , написана функция MyFunc . Вместо явного указания типа функции и типов параметров этой функции — было задействовано обозначение типа: просто тип. Наша буква T — это, в нашем случае, просто любой тип. В этот тип можно заслать любой тип данных: int, float, char*, MyClass — вообще любой.

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

Шаблоны (templates) - это механизм, позволяющий обобщать функции и классы для работы с различными типами данных.

Шаблоны обеспечивают непосредственную поддержку обобщенного программирования (т.е. c использованием типов в качестве параметров)

Шаблон зависит только от тех свойств параметра-типа, которые он явно использует

Существуют шаблоны функций и классов

Инстанцирование

Процесс порождения функции или класса из шаблона называется инстанцированием

Процесс генерации объявления класса по шаблону класса и аргументу шаблона

Версия шаблона для конкретного аргумента шаблона называется специализацией

Генерация версий шаблона - задача компилятора

1.1 Шаблоны функций

Для создания шаблона используется ключевое слово template. Также указывается пока неопределенный тип T.

Рассмотрим пример шаблонной функции swap для обмена значений двух переменных

Для получения функции проведем инстанцирование

Еще один пример: функция сортировки

Пример шаблона с целочисленным параметром

Примеры использования шаблонов

1.2 Шаблоны классов

Аналогично функциям можно создавать шаблоны классов. Рассмотрим пример стека:

Воспользоваться шаблоном класса можно так

Описание конструктора и деструктора шаблонного класса

Описание методов push и pop

Описание методов определения размера стека

Примеры инстанцирования

Рассмотрим примеры использования шаблона стека

1.3 Параметры шаблонов

Параметры шаблона

У шаблонов могут быть параметры различных типов

Инстанцирование выполняется с указанием значения параметра

В шаблонах допускается использование различных видов параметров

Если в шаблоне класса или функции необходимо использовать один и тот же шаблон, но с разными параметрами, то используются параметры-шаблоны. Например:

Перегрузка шаблонов

Специализация шаблонов

Явное инстанцирование

Явное инстанцирование используется

  1. Если инстанцирование шаблонов отнимает слишком много времени
  2. Если порядок компиляции должен быть абсолютно предсказуем

2 Специализация шаблонов

Для чего нужна специализация шаблонов? Для того чтобы задать шаблон для отдельного значения параметра (типа или значения).

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

Для строк создаётся специализация.

2.1 Класс Bag

Шаблон класса Bag

В следующем примере приводится шаблон класса Bag, который является

динамическим контейнером элементов и его специализация,

позволяющая задавать элементы не по значению, а по указателю.

2.2 Пример с наследованием

Мы можем использовать специализацию при наследовании.

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

если разработчику необходима информация о базовых классах объектов, основанных на шаблоне Derived. Как ее получить?

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

Описываем шаблон класса-наследника, в который помещается метод GetBaseClass

Использование шаблонов в C++

Программирование и разработка

Использование шаблонов в C++

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

Скалярные типы: void, bool, char, int, float и pointer.

Классы как типы

Конкретный класс можно рассматривать как тип, а его объекты — как возможные значения.

Универсальный тип представляет собой набор скалярных типов. Список скалярных типов обширен. Тип int, например, имеет другие связанные типы, такие как short int, long int и т. Д. Универсальный тип также может представлять набор классов.

Переменная

Пример объявления и определения шаблона следующий:

Прежде чем продолжить, обратите внимание, что такого рода операторы не могут появляться в функции main () или в любой области блока. Первая строка — это объявление заголовка шаблона с выбранным программистом универсальным именем типа T. Следующая строка — это определение идентификатора pi, который относится к универсальному типу T. Точность того, является ли T. int, float или какой-либо другой тип может быть выполнен в функции C ++ main () (или какой-либо другой функции). Такая точность будет сделана с переменной pi, а не T.

Первая строка — это объявление заголовка шаблона. Это объявление начинается с зарезервированного слова, шаблона, а затем с открытой и закрытой угловых скобок. В угловых скобках указан как минимум один идентификатор универсального типа, например T, указанный выше. Может быть несколько идентификаторов универсального типа, каждому из которых предшествует зарезервированное слово typename. Такие универсальные типы в этой позиции называются параметрами шаблона.

Следующий оператор может быть записан в main () или в любой другой функции:

И функция отобразит 3.14. Выражение pi определяет точный тип T для переменной pi. Специализация определяет конкретный тип данных для параметра шаблона. Создание экземпляра — это внутренний процесс C ++ по созданию определенного типа, такого как float, в данном случае. Не путайте создание экземпляра параметра шаблона и создание экземпляра класса. В теме шаблона многие типы данных могут иметь одно общее имя типа, тогда как многие классы могут иметь одно общее имя класса. Однако общее имя класса для классов просто называется классом, а не именем класса. Кроме того, значение относится к типу данных, например int, так же как созданный объект относится к классу, например классу String.

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

В специализации тип известен как аргумент шаблона. Не путайте это с аргументом функции для вызова функции.

Тип по умолчанию

Если при специализации тип не указан, предполагается тип по умолчанию. Итак, из следующего выражения:

Примечание: тип по умолчанию все еще можно изменить при специализации, установив другой тип.

Структура

В следующем примере показано, как параметр шаблона можно использовать со структурой:

template typename T > struct Ages
<
T John = 11 ;
T Peter = 12 ;
T Mary = 13 ;
T Joy = 14 ;
> ;

Это возраст учащихся класса (класса). Первая строка — это объявление шаблона. Тело в фигурных скобках — это фактическое определение шаблона. Возраст можно вывести в функции main () следующим образом:

Ages int > grade7 ;
cout grade7. John ‘ ‘ grade7. Mary ‘ \n ‘ ;

Результат: 11 13. Первый оператор здесь выполняет специализацию. Обратите внимание, как это было сделано. Он также дает имя для объекта структуры: grade7. Второй оператор имеет обычные выражения объекта структуры. Структура похожа на класс. Здесь Ages похож на имя класса, а grade7 — это объект класса (структура).

Если некоторые значения возраста являются целыми числами, а другие — числами с плавающей запятой, то структуре требуются два общих параметра, как показано ниже:

template typename T , typename U > struct Ages
<
T John = 11 ;
U Peter = 12.3 ;
T Mary = 13 ;
U Joy = 14.6 ;
> ;

Соответствующий код для функции main () выглядит следующим образом:

Ages int , float > grade7 ;
cout grade7. John ‘ ‘ grade7. Peter ‘ \n ‘ ;

Результат: 11 12.3. При специализации порядок типов (аргументов) должен соответствовать порядку универсальных типов в объявлении.

Объявление шаблона можно отделить от определения следующим образом:

template typename T , typename U > struct Ages
<
T John ;
U Peter ;
T Mary ;
U Joy ;
> ;

Ages int , float > grade7 = < 11 , 12.3 , 13 , 14.6 >;

Первый сегмент кода — это просто объявление шаблона (нет присваиваний). Второй сегмент кода, который является просто оператором, является определением идентификатора grade7. Слева — объявление идентификатора grade7. Справа находится список инициализаторов, который присваивает соответствующие значения элементам структуры. Второй сегмент (оператор) можно записать в функцию main (), в то время как первый сегмент остается вне функции main ().

Не тип

Примеры типов, не относящихся к данным, включают int, указатель на объект, указатель на функцию и типы auto. Есть и другие нетипы, которые в этой статье не рассматриваются. Нетип подобен неполному типу, значение которого задается позже и не может быть изменено. В качестве параметра он начинается с определенного не типа, за которым следует идентификатор. Значение идентификатора дается позже, при специализации, и не может быть изменено снова (как константа, значение которой задается позже). Следующая программа иллюстрирует это:

При специализации первый тип, int, в угловых скобках используется скорее для формальности, чтобы убедиться, что количество и порядок параметров соответствуют количеству и порядку типов (аргументов). Значение N дано при специализации. Результат: 11 14.6.

Частичная специализация

Предположим, что в шаблоне есть четыре универсальных типа и что среди четырех типов необходимы два типа по умолчанию. Это может быть достигнуто с помощью конструкции частичной специализации, в которой не используется оператор присваивания. Таким образом, конструкция частичной специализации дает значения по умолчанию для подмножества универсальных типов. Однако в схеме частичной специализации необходимы базовый класс (структура) и класс частичной специализации (структура). Следующая программа иллюстрирует это для одного универсального типа из двух универсальных типов:

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

Соответствующий код в функции main () может быть следующим:

Ages int , float > grade7 ;
cout grade7. John ‘ ‘ grade7. Joy ‘ \n ‘ ;

Результат: 11 14.6.

Пакет параметров шаблона

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

11 13
12,3 14,6
11 14,6
11 14,6

Шаблоны функций

Упомянутые выше возможности шаблона применяются аналогично шаблонам функций. В следующей программе показана функция с двумя общими параметрами шаблона и тремя аргументами:

Результат выглядит следующим образом:

В магазине 12 книг стоимостью 500 долларов.

Отделение от прототипа

Определение функции можно отделить от ее прототипа, как показано в следующей программе:

Примечание. Объявление шаблона функции не может появляться в функции main () или в любой другой функции.

Перегрузка

Перегрузка одной и той же функции может происходить с разными объявлениями заголовка шаблона. Следующая программа иллюстрирует это:

В магазине 12 книг стоимостью 500 долларов.

В магазине 12 книг стоимостью 500 долларов.

Шаблоны классов

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

Результат выглядит следующим образом:

В магазине 12 книг стоимостью 500 долларов.

Следующая программа представляет собой указанную выше программу с объявлением заголовка шаблона:

Вместо слова typename в списке параметров шаблона можно использовать слово class. Обратите внимание на специализацию в объявлении объекта. Результат все тот же:

В магазине 12 книг стоимостью 500 долларов.

Разделительная декларация

Объявление шаблона класса можно отделить от кода класса следующим образом:

Работа со статическими членами

В следующей программе показано, как получить доступ к статическому члену данных и статической функции-члену:

Присвоение значения статическому элементу данных является объявлением и не может быть в main (). Обратите внимание на использование и расположение универсальных типов и универсального типа данных в операторе присваивания. Кроме того, обратите внимание, что функция-член статических данных была вызвана в main () с фактическими типами данных шаблона. Результат следующий:

Официальная статическая функция-член.

Компиляция

Объявление (заголовок) и определение шаблона должны быть в одном файле. То есть они должны быть в одной единице перевода.

Заключение

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

Всем доброго времени суток. Начал читать про шаблоны, появились вопросы.
1. Как мне вывести реализацию addFix в cpp файл(мог перепутать терминологию и дабы не ругались, как правильно вынести то что в <> ), а то все время ошибки вылетают ?)))
2. Получаю соответственно ошибки при вызове функции с разными параметрами "Cannot convert 'TSystemObj *' to 'TTrans2Obmot *' и наоборот. ". Как сделать так, чтобы функция могла приниматься объекты разных типов ?


Шаблонная функция в отдельном cpp
Здравствуйте, Подскажите пожалуйста, вот когда обьявляю шаблонную функцию внутри main.cpp: .

Как вызвать в основном .cpp файле тот или иной .cpp файл
Ну, обычно я работал с одним .cpp но вот появилась надобность в основном файле написать интерфейс.

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


С помощью командной строки >namberstr f1.cpp Определить число строк в файле с именем f1.cpp
С помощью командной строки >namberstr f1.cpp Определить число строк в файле с именем f1.cpp

Решение

В отдельный файл выносить нельзя.
Шаблон, ведь, не компилируется, а инстанцируется по фактическому значению параметров.
Поэтому он должен присутствовать в том же файле, где вызывается.
Поэтому поместите его в .h файл.

Fobes, в cpp-файл вынести можно, но не нужно. Потому что в месте использования шаблона (в месте инстанцирования) должно быть доступно полное определение (иначе нельзя будет сгенерировать по шаблону функцию). Оставляй в h-файле как есть.

Если ты получаешь такие ошибки, то типы (указателей) действительно неприводимые, и затыкать компилятору рот через reinterpret_cast - это варварство. Лично мне кажется, что в твоем случае вообще не нужен никакой шаблон, достаточно обычной перегрузки, но если уж хочется его оставить, то я бы сделал так:

RTTI и шаблоны вещи ортогональные, шаблоны - это время компиляции, а RTTI - время выполнения. Поэтому проверка, которую ты пытался сделать, нужна на этапе компиляции, а не выполнения, и провести ее можно посредством разрешения перегрузки (неправильный код не скомпилируется).
Ну и в случае наследования от TSystemObj или TTrans2Obmot код останется корректным.

Шаблон с переменным числом аргументов ( С++11 ) - это шаблон класса или функции, поддерживающий произвольное число аргументов. Этот механизм особенно удобен для разработчиков библиотек C++, поскольку его можно применить к как к шаблонам классов, так и к шаблонам функций. Таким образом, он предоставляет широкий спектр широкий спектр типобезопасных и нетривиальных функций и гибких возможностей.

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

В приведенном выше примере параметр Arguments означает пакет параметров. При инстанцировании класс classname может принимать переменное число аргументов, как показано в следующих примерах:

Кроме того, определение шаблонного класса с переменным числом аргументов может устанавливать требование, что должен быть передан по меньшей мере один параметр:

Ниже представлен простейший пример синтаксиса для определения шаблонной функции с переменным числом аргументов.

Далее пакет параметров Arguments развертывается для использования, что бы показать что функция принимает переменное число аргументов.

Возможны и другие формы синтаксиса шаблонной функции с переменным количеством аргументов:

Шаблонные функции с переменным числом аргументов (как и аналогичные шаблонные классы) также могут устанавливать требование о том, что должен быть передан по меньшей мере один параметр.

В шаблонах с переменным числом аргументов используется оператор sizeof. () (он не имеет отношения к старому оператору sizeof()):

В списке-параметров-шаблона (template

) параметр typename. вводит в программу пакет параметров шаблона.

В предложении объявления параметра (func(parameter-list)) многоточие "верхнего уровня" вводит пакет параметров функции, и положение многоточия имеет большое значение.

Читайте также: