Шаблоны — это инструмент 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

#ifndef TEMPLATE_DEMO_HXX #define TEMPLATE_DEMO_HXX template<class T> class A{ public: T g(T a,T b); A(); }; #endif   TemplateDemo.cpp #include<iostream.h> #include "TemplateDemo.h" template<class T> A<T>::A(){} template<class T> T A<T>::g(T a,T b){ return a+b; } void main(){ A<int> a; cout<<a.g(2,3.2)<<endl; }

Результат компиляции:

--------------------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

#ifndef TEMPLATE_DEMO_HXX #define TEMPLATE_DEMO_HXX template<class T,int MAXSIZE> class Stack{//MAXSIZE задаётся пользователем при создании объекта private: T elems[MAXSIZE]; // Массив, содержащий элементы int numElems; // Текущее общее количество элементов public: Stack(); // Конструктор void push(T const&); // Поместить элемент void pop(); // Извлечь элемент T top() const; // Вернуть верхний элемент стека bool empty() const{ // Возвращает, пуст ли стек return numElems == 0; } bool full() const{ // Возвращает, полон ли стек return numElems == MAXSIZE; } }; template <class T,int MAXSIZE> Stack<T,MAXSIZE>::Stack():numElems(0){ // Изначально стек не содержит элементов // Ничего не делать } template <class T,int MAXSIZE> void Stack<T, MAXSIZE>::push(T const& elem){ if(numElems == MAXSIZE){ throw std::out_of_range("Stack<>::push(): стек полон"); } elems[numElems] = elem; // Добавить элемент ++numElems; // Увеличить количество элементов } template<class T,int MAXSIZE> void Stack<T,MAXSIZE>::pop(){ if (numElems <= 0) { throw std::out_of_range("Stack<>::pop(): пустой стек"); } --numElems; // Уменьшить количество элементов } template <class T,int MAXSIZE> T Stack<T,MAXSIZE>::top()const{ if (numElems <= 0) { throw std::out_of_range("Stack<>::top(): пустой стек"); } return elems[numElems-1]; // Вернуть последний элемент } #endif

TemplateDemo.cpp

#include<iostream.h> #include <iostream> #include <string> #include <cstdlib> #include "TemplateDemo.h" int main(){ try { Stack<int,20> int20Stack; // Стек, который может хранить 20 элементов int Stack<int,40> int40Stack; // Стек, который может хранить 40 элементов int Stack<std::string,40> stringStack; // Стек, который может хранить 40 элементов string // Используйте стек, который может хранить 20 элементов int int20Stack.push(7); std::cout << int20Stack.top() << std::endl; //7 int20Stack.pop(); // Используйте стек, который может хранить 40 элементов string stringStack.push("hello"); std::cout << stringStack.top() << std::endl; //hello stringStack.pop(); stringStack.pop(); //Исключение: Stack<>::pop<>: пустой стек return 0; } catch (std::exception const& ex) { std::cerr << "Exception: " << ex.what() << std::endl; return EXIT_FAILURE; // Завершить программу с флагом ОШИБКИ } }

Пример 2 демонстрации нетипового параметра:

TemplateDemo01.h

#ifndef TEMPLATE_DEMO_O1 #define TEMPLATE_DEMO_01 template<typename T> class CompareDemo{ public: int compare(const T&, const T&); }; template<typename T> int CompareDemo<T>::compare(const T& a,const T& b){ if((a-b)>0) return 1; else if((a-b)<0) return -1; else return 0; } #endif

TemplateDemo01.cpp

#include<iostream.h> #include "TemplateDemo01.h" void main(){ CompareDemo<int> cd; cout<<cd.compare(2,3)<<endl; }

Результат выполнения:-1 

TemplateDemo01.cpp

#include<iostream.h> #include "TemplateDemo01.h" void main(){ CompareDemo<double> cd; cout<<cd.compare(3.2,3.1)<<endl; }

Результат выполнения:1 

 

TemplateDemo01.h

#ifndef TEMPLATE_DEMO_O1 #define TEMPLATE_DEMO_01 template<typename T> class CompareDemo{ public: int compare(T&, T&); }; template<typename T> int CompareDemo<T>::compare(T& a,T& b){ if((a-b)>0) return 1; else if((a-b)<0) return -1; else return 0; } #endif

TempalteDemo01.cpp

#include<iostream.h> #include "TemplateDemo01.h" void main(){ CompareDemo<int> cd; int a=2,b=3; cout<<cd.compare(a,b)<<endl; }

Пример 3 демонстрации нетипового параметра:

TemplateDemo02.cpp

#include<iostream.h> template<typename T> const T& max(const T& a,const T& b){ return a>b ? a:b; } void main(){ cout<<max(2.1,2.2)<<endl;// Аргумент шаблона неявно выводится как double cout<<max<double>(2.1,2.2)<<endl;// Явно указываем параметры шаблона. cout<<max<int>(2.1,2.2)<<endl;// Явно указанные параметры шаблона напрямую преобразуют параметр функции в int. }

Результат выполнения:

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

#ifndef TEMPLATE_DEMO_HXX #define TEMPLATE_DEMO_HXX template<class T> class A{ public: T g(T a,T b); A(); }; #endif

TemplateDemo.cpp

#include<iostream.h> #include "TemplateDemo.h" template<class T> A<T>::A(){} template<class T> T A<T>::g(T a,T b){ return a+b; } void main(){ A<int> a; cout<<a.g(2,3)<<endl; }

Результат выполнения:5

Пример 1 параметров типа шаблона по умолчанию для шаблонов классов:

TemplateDemo03.h

#ifndef TEMPLATE_DEMO_03 #define TEMPLATE_DEMO_03 // Определение шаблона класса с параметром типа по умолчанию. Здесь T2 по умолчанию установлен в int. template<class T1,class T2=int> class CeilDemo{ public: int ceil(T1,T2); }; // При определении членов класса вне шаблона класса в списке параметров после 'template' следует опускать типы параметров по умолчанию. template<class T1,class T2> int CeilDemo<T1,T2>::ceil(T1 a,T2 b){ return a>>b; } #endif

TemplateDemo03.cpp

#include<iostream.h> #include "TemplateDemo03.h" void main(){ CeilDemo<int> cd; cout<<cd.ceil(8,2)<<endl; }

Результат выполнения: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

#ifndef TEMPLATE_DEMO_03 #define TEMPLATE_DEMO_03 template<class T1=int,class T2,class T3> class CeilDemo{ public: int ceil(T1,T2,T3); }; template<class T1,class T2,class T3> int CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){ return a+b+c; } #endif

TemplateDemo03.cpp

#include<iostream.h> #include "TemplateDemo03.h" void main(){ CeilDemo<int,int> cd; cout<<cd.ceil(2,3,4)<<endl; }

Результат выполнения:9  

TemplateDemo03.h

#ifndef TEMPLATE_DEMO_03 #define TEMPLATE_DEMO_03 template<class T1=int,class T2,class T3> class CeilDemo{ public: double ceil(T1,T2,T3); }; template<class T1,class T2,class T3> double CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){ return a+b+c; } #endif

TemplateDemo03.cpp

#include<iostream.h> #include "TemplateDemo03.h" void main(){ CeilDemo<double,double> cd; cout<<cd.ceil(2,3.1,4.1)<<endl; }

Ошибка компиляции:

--------------------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

#ifndef TEMPLATE_DEMO_03 #define TEMPLATE_DEMO_03 template<class T1=int,class T2=double,class T3=double> class CeilDemo{ public: double ceil(T1,T2,T3); }; template<class T1,class T2,class T3> double CeilDemo<T1,T2,T3>::ceil(T1 a,T2 b,T3 c){ return a+b+c; } #endif

TemplateDemo03.cpp

#include<iostream.h> #include "TemplateDemo03.h" void main(){ CeilDemo<int,double,double> cd; cout<<cd.ceil(2,3.1,4.1)<<endl; }

Ошибка компиляции:

--------------------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

#include<iostream.h> template<class T1,class T2,class T3> T1 sum(T1 a,T2 b,T3 c=int){ return a+b+c; } void main(){ cout<<sum<double,double>(1.1,2.1,3)<<endl; }

Ошибка компиляции:

--------------------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

#include<iostream.h> template<class T1,class T2,class T3> T1 sum(T1 a,T2 b,T3 c){ return a+b+c; } void main(){ cout<<sum<double,short,int>(1.1,3,257)<<endl; }

Результат выполнения:261.1 

    

Демонстрационный пример оригинального автора выглядит следующим образом:

Пример нетиповых параметров в шаблонах классов

// Объявление или определение шаблона можно выполнять только в глобальной области видимости, области видимости пространства имён или класса. То есть это нельзя делать в локальной области видимости или внутри функции; например, шаблон нельзя объявить или определить в функции main. // Определение шаблона класса template<class T>class A{public:T g(T a, T b); A();}; // Определение класса A с одним параметром типа шаблона класса T template<class T1,class T2>class B{public:void g();}; // Определение класса B с двумя параметрами типа шаблона класса T1, T2 // Определение параметров типа по умолчанию для шаблонов классов; параметры типа по умолчанию не подходят для шаблонов функций. template<class T1,class T2=int> class D{public: voidg();}; // Определение шаблона класса с параметрами типа по умолчанию. Здесь T2 по умолчанию установлен в int. //template<class T1=int, class T2>class E{}; // Ошибка: если для T1 задан тип параметра по умолчанию, то все параметры после T1 также должны иметь значения по умолчанию. // Ниже приведены определения нетиповых параметров // Нетиповые параметры могут быть только целочисленными типами, указателями и ссылками. Такие типы, как double, String, String **, не допускаются. Однако double &, double * (ссылки или указатели на объекты) являютсякорректными.template<class T1,int a> class Ci{public:void g();}; // Определите нетиповой параметр шаблона, где параметр имеет целочисленный тип template<class T1,int &a>class Cip{public:void g();}; template<class T1,A<int>* m> class Cc{public:void g();}; // Определите нетиповой параметр шаблона, где параметр — указатель на объект класса A типа int. template<class T1,double*a>class Cd{public:void g();}; // Определите нетиповой параметр шаблона, где параметр — ссылка типа double. class E{}; template<class T1,E &m> class Ce{}; // Нетиповой параметр шаблона — ссылка на объект. // Следующие объявления нетиповых параметров неверны. //template<class T1,A m>class Cc{}; // Ошибка: объект нельзя использовать в качестве нетипового параметра; тип нетипового параметра шаблона может быть только ссылкой или указателем на объект. //template<class T1,double a>class Cc{}; // Ошибка: параметр нетипового шаблона не может иметь тип double; он может быть ссылкой на double. //template<class T1,A<int> m>class Cc{}; // Ошибка: параметр нетипового шаблона не может быть объектом; он должен быть ссылкой или указателем на объект. Это правило также применяется к параметрам шаблонабез исключения.// Методы определения различных членов класса вне шаблона класса, //Функция typeid(имя переменной).name() предназначена для извлечения типа переменной. Например, int a, тогда cout<<typeid(a).name() выведет int. template<class T> A<T>::A(){cout<<"class A конструктор"<<typeid(T).name()<<endl;} //Метод определения конструктора класса вне шаблона класса template<class T> T A<T>::g(T a,T b){cout<<"class A g(T a,T b)"<<endl;} //Определение членов шаблона класса вне шаблона класса template<class T1,class T2> voidB<T1,T2>::g(){cout<<"class g f()"<<typeid(T1).name()<<typeid(T2).name()<<endl;} //При определении членов класса вне класса параметры шаблона после template должны соответствовать параметрам шаблона определяемого класса. template<class T1,int a> voidCi<T1,a>::g(){cout<<"class Ci g()"<<typeid(T1).name()<<endl;} template<class T1,int &a> voidCip<T1,a>::g(){cout<<"class Cip g()"<<typeid(T1).name()<<endl;} //При определении членов класса вне класса параметры шаблона после template должны соответствовать параметрам шаблона определяемого класса. template<class T1,A<int> *m> voidCc<T1,m>::g(){cout<<"class Cc g()"<<typeid(T1).name()<<endl;} template<class T1,double* a> voidCd<T1,a>::g(){cout<<"class Cd g()"<<typeid(T1).name()<<endl;} //Метод определения членов вне класса для шаблонного класса с параметрами типа по умолчанию. //При определении членов класса вне класса значения по умолчанию в списке параметров шаблона следует опускать. template<class T1,class T2> voidD<T1,T2>::g(){cout<<"class D g()"<<endl;} //template<class T1,class T2=int> void D<T1,T2>::g(){cout<<"class D k()"<<endl;} //ошибка: при определении шаблона с типом по умолчанию вне класса-шаблона формальныйпараметр, вtemplateзначение по умолчанию в списке параметров должно быть опущено.//Определить несколько глобальных переменных. int e=2; doubleed=2.2; double*pe=&ed; A<int> mw; A<int> *pec=&mw; E me; //начинается функция main int main() { // template<class T>void h(){} //ошибка: объявления или определения шаблонов могут находиться только в глобальной области видимости, области видимости пространства имён или области видимости класса. То есть они не могут находиться в локальной области видимости или внутри функции. //A<2> m; //ошибка, для шаблонов классов нет вывода аргументов; тип должен быть явно указан в угловых скобках. //Пример вызова шаблона класса A<int> ma; //Вывод "class A goucao int" создаёт объект ma шаблона класса A с типом int. B<int,int> mb; mb.g(); //Вывод "class B g() int int" создаёт объект mb шаблона класса B с параметрами типа T1 и T2, установленными в int. //Вызов нетипового параметра //Аргумент для нетипового параметра шаблона должен быть константным выражением, т. е. он должен быть вычислимым во время компиляции. Любой локальный объект, локальная переменная, адрес локального объекта, локальныеадреса переменных не являются константными выражениями и не могут использоваться в качестве аргументов для нетиповых параметров шаблона. Глобальные типы указателей, глобальные переменные и глобальные объекты также не являются константными выражениями и не могут//Адрес или ссылка на глобальную переменную, адрес или ссылка на глобальный объект, или переменная типа const является константным выражением и может использоваться в качестве аргумента для нетипового параметра шаблона. //Метод вызова нетипового параметра int называется Ci, объявлен как template<class T1,int a> class Ci Ci<int,3>//Верно, значение R — это int-константа, вывод "class Ci g() int" const int a2=3; Ci<int,a2> mci1; mci1.g(); //Верно, потому что a2 здесь является константой const. Вывод "class Ci g() int" //Ci<int,a> mci; //ошибка: int-переменная a является локальной переменной и не является константным выражением. //Ci<int,e> mci; //ошибка: глобальная int-переменная e также не является константным выражением. //Способ вызова нетипового параметра int& имеет имя класса Cip, объявленного как template<class T1,int &a>class Cip Cip<int,e> mcip; //Верно: ссылка или адрес глобальной переменной является константным выражением. //Cip<int,a> mcip1; //ошибка: ссылка или адрес локальной переменной не является константным выражением. //Способ вызова нетипового параметра double* имеет имя класса Cd, объявленного как template<class T1,double *a>class Cd Cd<int,&ed> mcd; //Верно: ссылка или адрес глобальной переменной является константным выражением. //Cd<int,pe> mcd1; //ошибка: указатель на глобальную переменную не является константным выражением. //double dd=3.3; //ошибка: адрес локальной переменной не является константным выражением и не может использоваться в качестве аргумента для нетипового параметра //Cd<int,&e> mcd; //ошибка: хотя для нетиповых параметров допускаются некоторые преобразования, это преобразование не может быть выполнено. //Способ вызова параметра шаблонного типа — объекта A<int>* — имеет имя класса Cc, объявленного как template<class T1,A<int>* m> class Cc Cc<int,&mw> mcc; mcc.g(); //Верно: адрес или ссылка на глобальный объект является константным выражением. //Cc<int,&ma> mcc; //ошибка: адрес или ссылка на локальную переменную не является константным выражением. //Cc<int,pec> mcc2; //ошибка: указатель на глобальный объект не является константным выражением. //Способ вызова нетипового параметра, являющегося ссылкой на объект E&, имеет имя класса Ce. Форма объявления: template<class T1,E &m> class Ce E me1; //Ce<int,me1> mce1; //ошибка, локальный объект не является константным выражением Ce<int,me> mce; //Правильно, указатель или ссылка на глобальный объект является константным выражением. //Пример преобразований для нетиповых параметров, имя класса Ci //Нетиповые параметры допускают преобразования массива в указатель, функции в указатель, преобразования квалификатора const, преобразования повышения, целочисленные преобразования и обычные преобразования. const short s=3; Ci<int,s> mci4†//Правильно, хотя short и int точно не совпадают, здесь short может быть преобразован в int

Исходный адрес:

https://www.cnblogs.com/gw811/archive/2012/10/25/2738929.html

http://www.cnblogs.com/gw811/archive/2012/10/25/2736224.html