Шаблоны — это инструмент C++ для поддержки параметрического полиморфизма. С помощью шаблонов пользователи могут объявить общую схему для классов или функций, позволяя некоторым элементам данных класса или параметрам и возвращаемым значениям функций-членов принимать произвольные типы.
Шаблон — это инструмент, который параметризует типы;
Обычно существует две формы: шаблоны функций и шаблоны классов;
Шаблоны функций предназначены для функций, которые отличаются только типами параметров;
Шаблоны классов предназначены для классов, которые отличаются только типами элементов данных и функций-членов.
Цель использования шаблонов — позволить программистам писать код, не зависящий от типа. Например, если вы напишете функцию swap, которая обменивает значения двух переменных int, эта функция сможет работать только с int. Она не сможет работать с такими типами, как double или char. Чтобы обменивать значения этих типов, вам придётся написать другую функцию swap. Цель использования шаблонов — сделать реализацию программы независимой от типа. Например, шаблонная функция swap может обрабатывать обмен как для int, так и для double. Шаблоны можно применять к функциям и классам. Ниже они рассматриваются по отдельности.
Примечание:Объявление или определение шаблона может находиться только в глобальной области видимости, области видимости пространства имён или класса. То есть оно не может находиться в локальной области видимости или внутри функции; например, нельзя объявить или определить шаблон в функции main.
I. Общая форма шаблонов функций
1. Формат шаблона функции:
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
函数体
}
Среди них template и class — ключевые слова. class можно заменить ключевым словом typename. Здесь typename и class не имеют различий. Параметры внутри <> называются параметрами шаблона. Параметры шаблона очень похожи на параметры функции. Параметры шаблона не могут быть пустыми. После объявления шаблонной функции можно использовать имена параметров шаблона для объявления переменных-членов и функций-членов в классе; то есть везде, где в этой функции можно использовать встроенные типы, можно использовать имена параметров шаблона. Параметры шаблона должны быть инициализированы аргументами шаблона, предоставленными при вызове шаблонной функции. Как только компилятор определит фактический тип аргумента шаблона, говорят, что он создал экземпляр шаблона функции. Например, шаблонная форма функции swap имеет вид:
template <class T> void swap(T& a, T& b){},
При вызове такой шаблонной функции тип T заменяется типом, использованным в вызове, напримерswap(a,b)гдеaиbявляютсяintтип, и в этот момент параметры в шаблонной функции swapTбудутintзаменены, и шаблон станетswap(int &a, int &b). А когдаswap(c,d)гдеcиdДаdoubleтип, шаблонная функция будет заменена наswap(double &a, double &b), таким образом достигается код, реализация функции в котором не зависит от типа.
2. Примечание: для шаблонов функций не существуетh(int,int)такого вызова,Тип параметров шаблона нельзя указывать в аргументах вызова функции. В вызовах шаблонов функций следует использоватьвывод аргументоввыполняться, то есть можно делать только h(2,3)такие вызовы, илиint a, b; h(a,b)。
Примеры демонстрации шаблонов функций будут рассмотрены ниже!
II. Общая форма шаблонов классов
1. Формат шаблона класса таков:
template<class 形参名,class 形参名,…> class 类名
{ ... };
Как шаблоны классов, так и шаблоны функций начинаются с template, за которым следует список параметров шаблона. Параметры шаблона не могут быть пустыми. После объявления шаблона класса можно использовать имена параметров шаблона класса для объявления переменных-членов и функций-членов в классе. То есть везде, где в классе можно использовать встроенные типы, для объявления можно использовать имена параметров шаблона. Например
template<class T> class A{public: T a; T b; T hy(T c, T &d);};
В классе A объявлены две переменные-члены a и b типа T, а также объявлена функция hy с типом возвращаемого значения T и двумя параметрами типа T.
2. Создание объекта шаблона класса: например, шаблонный классA, тогда способ создания объекта с использованием шаблона класса таков:A<int> m;После классаAследует<>угловая скобка, и внутри указываются соответствующие типы. Таким образом, классAвезде, где в классе используются параметры шаблона, будутintзаменены. Когда шаблон класса имеет два параметра шаблона, способ создания объекта таков:A<int, double> m;Разделяйте типы запятыми.
3. Для шаблонов классов типы параметров шаблона должны быть явно указаны в угловых скобках после имени класса. НапримерA<2> m;Установка параметра шаблона вintневерна (Ошибка компиляции: error C2079: 'a' uses undefined class 'A<int>'),Параметры шаблона класса не имеют проблемы вывода аргументов.То есть целочисленное значение не может быть2выведено какint-тип и передано в параметр шаблона. Чтобы задать параметр шаблона класса равнымintтип, его нужно указывать так:A<int> m。
4. Способ определения функций-членов вне шаблона класса:
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
Например, если класс A с двумя параметрами шаблона T1 и T2 содержит функцию void h(), синтаксис определения этой функции таков:
template<class T1,class T2> void A<T1,T2>::h(){}。
Примечание:При определении членов класса вне класса параметры шаблона после template должны совпадать с параметрами шаблона определяемого класса.
5. Напоминание ещё раз: объявление или определение шаблона может находиться только в глобальной области видимости, области видимости пространства имён или класса. То есть оно не может находиться в локальной области видимости или внутри функции; например, оно не может быть в функцииmainдля объявления или определения шаблона.
III. Параметры шаблона
Существует три типа параметров шаблона: параметры типа, нетиповые параметры и параметры-шаблоны.
1. Параметры типа
1.1 Параметры типа шаблона:Параметр типа состоит из ключевого слова class или typename, за которым следует спецификатор, напримерtemplate<class T> void h(T a){}; гдеT— параметр типа. Имя параметра типа определяется пользователем самостоятельно.Параметр шаблона представляет неизвестный тип.Параметр типа шаблона можно использовать как спецификатор типа в любом месте шаблона, точно так же, как встроенные спецификаторы типа или спецификаторы типа класса; то есть его можно использовать для указания возвращаемых типов, объявлений переменных и т. д.
Исходная версия автора:1.2, Нельзя указать два разных типа для одного и того же параметра типа шаблона. Например,template<class T>void h(T a, T b){},инструкция вызоваh(2, 3.2)приведёт к ошибке, потому что инструкция указывает для одного и того же параметра шаблона,Tдва типа. Первый аргумент2задаёт параметр шаблона T какint, тогда как второй аргумент3.2задаёт параметр шаблона какdouble, два типа параметров несовместимы, что приводит к ошибке.(Применимо к шаблонам функций)
Исходная версия автора: 1.2 верна для шаблонов функций, но игнорирует шаблоны классов. Ниже будет дополнена ситуация с шаблонами классов.
Моя дополненная версия 1.2 (для шаблонов классов):Когда мы объявляем объект класса как:A<int> a, напримерtemplate<class T>T g(T a, T b){}, инструкция вызоваa.g(2, 3.2)не приведёт к ошибке во время компиляции, но появится предупреждение, потому что при объявлении объекта класса он ужеTпреобразован к типуint, тогда как второй аргумент3.2задаёт параметр шаблона какdouble, во время выполнения он3.2выполнит принудительное преобразование типа к3. Когда мы объявляем объект класса как:A<double> a, в этом случае такого предупреждения не будет, потому что изintвdouble— это автоматическое преобразование типа.
Демонстрационный пример 1:
TemplateDemo.h
Результат компиляции:
--------------------Configuration: TemplateDemo - Win32 Debug-------------------- Compiling... TemplateDemo.cpp G:\C++\CDaima\TemplateDemo\TemplateDemo.cpp(12) : warning C4244: 'argument' : conversion from 'const double' to 'int', possible loss of data TemplateDemo.obj - 0 error(s), 1 warning(s)
Результат выполнения:5
Из приведённого выше тестового примера видно, что это не так строго, как в оригинальной работе автора! Это лишь мой личный результат тестирования! Пожалуйста, отнеситесь к этому практически и в духе поиска истины и проверьте сами!
2. Нетиповые параметры
2.1 Нетиповые параметры шаблона:Нетиповой параметр шаблона — это параметр встроенного типа, напримерtemplate<class T, int a> class B{};гдеint aявляется нетиповым параметром шаблона.
2.2 Нетиповые параметры являются постоянными значениями внутри определения шаблона; то есть нетиповые параметры — это константы внутри шаблона.
2.3, Нетиповыешаблонныепараметры могут быть только целочисленными типами, указателями и ссылками, типы, такие как double, String и String**, не допускаются.Ноdouble &,double *,ссылки или указатели на объекты допустимы.
2.4, Аргумент нетипового параметра шаблона должен быть константным выражением,то есть он должен быть вычислим во время компиляции.
2.5 Примечание:Любой локальный объект, локальная переменная, адрес локального объекта или адрес локальной переменной не являются константным выражением и не могут использоваться в качестве аргумента для нетипового параметра шаблона.Глобальные типы указателей, глобальные переменные и глобальные объекты также не являются константными выражениями и не могут использоваться в качестве аргументов для нетиповых параметров шаблона.
2.6, ; A<b> m; то есть преобразование массива в указатель.。
2.7 、sizeofРезультат выражения является константным выражением, и его также можно использовать в качестве аргумента для нетипового параметра шаблона.
2.8. Когда параметр шаблона имеет целочисленный тип, аргумент, используемый при вызове шаблона, должен быть целочисленного типа и должен быть константой во время компиляции. Например,template <class T, int a> class A{};Если естьint b, то A<int, b> m;вызовет ошибку, потому чтоbb не является константой. Еслиconst int b, то A<int, b> m; правильно, потому что в этом случаеbb является константой.
2.9 、Нетиповые параметры обычно не используются в шаблонах функций.Например, есть шаблон функцииtemplate<class T, int a> void h(T b){}, если использоватьh(2)для его вызова, возникнет ошибка, указывающая, что аргумент для нетипового параметра a невозможно вывести. Для такой шаблонной функции можно использовать явные аргументы шаблона, чтобы решить проблему, например h<int, 3>(2), что устанавливает нетиповой параметр a в целое число 3. Явные аргументы шаблона будут представлены позже.
2.10. Допустимые преобразования между параметром и аргументом нетиповых параметров шаблона
1. Разрешаются преобразования из массива в указатель и из функции в указатель. Например: template <int *a> class A{}; int b
2. Преобразование квалификатора const. Например: template<const int *a> class A{}; int b; A<&b> m; то есть преобразование из int * в const int *.
3. Преобразование с повышением. Например: template<int a> class A{}; const short b=2; A<b> m; то есть преобразование с повышением из short в int.
4. Целочисленное преобразование. Например: template<unsigned int a> class A{}; A<3> m; то есть преобразование из int в unsigned int.
5. Обычные преобразования.
Пример 1 демонстрации нетипового параметра:
Пользователь сам задаёт размер стека и реализует связанные со стеком операции.
TemplateDemo.h
TemplateDemo.cpp

Пример 2 демонстрации нетипового параметра:
TemplateDemo01.h
TemplateDemo01.cpp
Результат выполнения:-1
TemplateDemo01.cpp
Результат выполнения:1
TemplateDemo01.h
TempalteDemo01.cpp
Пример 3 демонстрации нетипового параметра:
TemplateDemo02.cpp
Результат выполнения:

cout<<max<int>(2.1,2.2)<<endl; //显示指定的模板参数,会将函数函数直接转换为int.
Эта инструкция вызовет предупреждение:
--------------------Configuration: TemplateDemo02 - Win32 Debug-------------------- Compiling... TemplateDemo02.cpp G:\C++\CDaima\TemplateDemo02\TemplateDemo02.cpp(11) : warning C4244: 'argument' : conversion from 'const double' to 'const int', possible loss of data G:\C++\CDaima\TemplateDemo02\TemplateDemo02.cpp(11) : warning C4244: 'argument' : conversion from 'const double' to 'const int', possible loss of data TemplateDemo02.obj - 0 error(s), 2 warning(s)
IV. Параметры типа шаблона класса по умолчанию
1, Для параметров типа шаблонов классов можно задавать значения по умолчанию, но для параметров типа шаблонов функций значения по умолчанию задавать нельзя.Как шаблоны функций, так и шаблоны классов могут задавать значения по умолчанию для нетиповых параметров шаблона.
2. Форма значений по умолчанию для параметров типа шаблона класса такова:template<class T1, class T2=int> class A{};для второго параметра типа шаблонаT2задайтеintв качестве значения по умолчанию типа ...
3. Значения по умолчанию для параметров типа шаблона класса такие же, как параметры по умолчанию функций. Если имеется несколько параметров типа, то все параметры шаблона после первого параметра, имеющего значение по умолчанию, также должны иметь значения по умолчанию. Например,template<class T1=int, class T2>class A{};это неправильно, потому чтоT1значение по умолчанию задано для ..., тогда какT2значение по умолчанию не задано для ...
4. При определении членов класса вне шаблона класса,templateв списке параметров после 'template' следует опускать типы параметров по умолчанию. Например,template<class T1, class T2=int> class A{public: void h();}; способ определения таков:template<class T1,class T2> void A<T1,T2>::h(){}。
Определение параметров типа шаблона класса:
Демонстрационный пример 1:
TemplateDemo.h
TemplateDemo.cpp
Результат выполнения:5
Пример 1 параметров типа шаблона по умолчанию для шаблонов классов:
TemplateDemo03.h
TemplateDemo03.cpp
Результат выполнения:2
При определении членов класса вне шаблона класса список параметров после 'template' должен опускать типы параметров по умолчанию. Если их не опустить, это не вызовет ошибки компиляции, но выдаст предупреждение:
--------------------Configuration: TemplateDemo03 - Win32 Debug-------------------- Compiling... TemplateDemo03.cpp g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : warning C4519: default template arguments are only allowed on a class template; ignored TemplateDemo03.obj - 0 error(s), 1 warning(s)
Автор оригинала:Значения по умолчанию для параметров типа шаблона класса такие же, как параметры по умолчанию функций. Если имеется несколько параметров типа, то все параметры шаблона после первого параметра, имеющего значение по умолчанию, также должны иметь значения по умолчанию. Например,template<class T1=int, class T2>class A{};это неправильно, потому чтоT1значение по умолчанию задано для ..., тогда какT2значение по умолчанию не задано для ...
Пример 2 значений по умолчанию параметров типа шаблона для шаблонов классов:
TemplateDemo03.h
TemplateDemo03.cpp
Результат выполнения:9
TemplateDemo03.h
TemplateDemo03.cpp
Ошибка компиляции:
--------------------Configuration: TemplateDemo03 - Win32 Debug-------------------- Compiling... TemplateDemo03.cpp g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2065: 'cd' : undeclared identifier g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2228: left of '.ceil' must have class/struct/union type Error executing cl.exe. TemplateDemo03.obj - 3 error(s), 0 warning(s)
Из приведённого выше примера видно, что когда мы пытаемся определить T2 и T3 как типы double, возникает ошибка (T1 по умолчанию определён как int). Так если мы последуем утверждению автора и также установим T2 и T3 в значение по умолчанию double, возникнет ли ошибка по-прежнему? Посмотрите на следующий пример:
Пример 4. Параметры типа шаблона по умолчанию для шаблонов классов:
TemplateDemo03.h
TemplateDemo03.cpp
Ошибка компиляции:
--------------------Configuration: TemplateDemo03 - Win32 Debug-------------------- Compiling... TemplateDemo03.cpp g:\c++\cdaima\templatedemo03\templatedemo03.h(12) : error C2244: 'CeilDemo<T1,T2,T3>::ceil' : unable to resolve function overload g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2065: 'cd' : undeclared identifier g:\c++\cdaima\templatedemo03\templatedemo03.cpp(6) : error C2228: left of '.ceil' must have class/struct/union type Error executing cl.exe. TemplateDemo03.obj - 3 error(s), 0 warning(s)
Из результатов видно, что это та же ошибка, что и в предыдущем примере. Из примеров можно сделать следующий вывод: если у шаблона класса несколько параметров типа и используются значения по умолчанию для параметров типа, их следует по возможности размещать в конце списка параметров, и типы параметров по умолчанию должны совпадать. Если для первого параметра задано значение по умолчанию, то для всех параметров шаблона после него также должны быть заданы значения по умолчанию того же типа, что и у первого параметра.(Заявление: я тоже новичок в C++. Выше приведены лишь некоторые вопросы, которые я задал об авторе оригинала после демонстраций на примерах. В моих примерах могут быть недостатки. Надеюсь, эксперты не откажутся дать советы, чтобы мы могли совместно улучшить этот блог и создать обучающую платформу для таких новичков, как я!)
Далее давайте проверим, что «для параметров типа шаблонов функций нельзя задавать значения по умолчанию»:
Пример 5: параметры типа по умолчанию для шаблонов классов:
TemplateDemo04.cpp
Ошибка компиляции:
--------------------Configuration: TemplateDemo04 - Win32 Debug-------------------- Compiling... TemplateDemo04.cpp g:\c++\cdaima\templatedemo04\templatedemo04.cpp(4) : error C2062: type 'int' unexpected Error executing cl.exe. TemplateDemo04.obj - 1 error(s), 0 warning(s)
Изменённый TemplateDemo.cpp
TemplateDemo.cpp
Результат выполнения:261.1
Демонстрационный пример оригинального автора выглядит следующим образом:
Пример нетиповых параметров в шаблонах классов
Исходный адрес:
https://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html
http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html