Template functions in cpp

Function Templates

Class templates define a family of related classes that are based on the type arguments passed to the class upon instantiation. Function templates are similar to class templates but define a family of functions. With function templates, you can specify a set of functions that are based on the same code but act on different types or classes. The following function template swaps two items:

// function_templates1.cpp template < class T >void MySwap( T& a, T& b ) < T c(a); a = b; b = c; >int main()

This code defines a family of functions that swap the values of the arguments. From this template, you can generate functions that will swap int and long types and also user-defined types. MySwap will even swap classes if the class’s copy constructor and assignment operator are properly defined.

In addition, the function template will prevent you from swapping objects of different types, because the compiler knows the types of the a and b parameters at compile time.

Although this function could be performed by a nontemplated function, using void pointers, the template version is typesafe. Consider the following calls:

int j = 10; int k = 18; CString Hello = "Hello, Windows!"; MySwap( j, k ); //OK MySwap( j, Hello ); //error 

The second MySwap call triggers a compile-time error, because the compiler cannot generate a MySwap function with parameters of different types. If void pointers were used, both function calls would compile correctly, but the function would not work properly at run time.

Читайте также:  Html как сделать head

Explicit specification of the template arguments for a function template is allowed. For example:

// function_templates2.cpp template void f(T) <> int main(int j) < f(j); // Generate the specialization f(char). // If not explicitly specified, f(int) would be deduced. > 

When the template argument is explicitly specified, normal implicit conversions are done to convert the function argument to the type of the corresponding function template parameters. In the above example, the compiler will convert j to type char .

Источник

Шаблоны (C++)

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

Определение и использование шаблонов

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

template T minimum(const T& lhs, const T& rhs)

Приведенный выше код описывает шаблон для универсальной функции с одним параметром типа T, возвращаемое значение и параметры вызова которого (lhs и rhs) относятся к этому типу. Параметру типа можно присвоить любое имя, но по соглашению чаще всего используются отдельные прописные буквы. T — параметр шаблона; в typename ключевое слово указано, что этот параметр является заполнителем для типа. При вызове функции компилятор заменяет каждый экземпляр на конкретный T аргумент типа, указанный пользователем или выведенный компилятором. Процесс, в котором компилятор создает класс или функцию из шаблона, называется создание экземпляра шаблона; minimum — это экземпляр шаблона minimum .

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

int a = get_a(); int b = get_b(); int i = minimum(a, b); 

Однако поскольку это шаблон функции, и компилятор может вывести тип T из аргументов a и b, его можно вызвать так же, как обычную функцию:

Когда компилятор обнаруживает этот последний оператор, он создает новую функцию, в которой каждое вхождение T в шаблоне заменяется int на :

int minimum(const int& lhs, const int& rhs)

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

Параметры типа

Обратите внимание, что в приведенном minimum выше шаблоне параметр типа T не является квалифицированным, пока он не будет использоваться в параметрах вызова функции, где добавляются квалификаторы const и ссылок.

Количество параметров типа практически не ограничено. Разделяйте несколько параметров запятыми:

В этом контексте ключевое слово class эквивалентно typename . Предыдущий пример можно выразить следующим образом:

Оператор с многоточием (. ) можно использовать для определения шаблона, который принимает произвольное число параметров типа (ноль или больше):

template class vtclass; vtclass < >vtinstance1; vtclass vtinstance2; vtclass vtinstance3; 

В качестве аргумента типа можно использовать любой встроенный или определяемый пользователем тип. Например, можно использовать std::vector в стандартной библиотеке для хранения переменных типа int , double , std::string, MyClass , const MyClass *, MyClass& и т. д. Основное ограничение при использовании шаблонов заключается в том, что аргумент типа должен поддерживать любые операции, применяемые к параметрам типа. Например, если мы вызываем minimum с помощью MyClass как в этом примере:

class MyClass < public: int num; std::wstring description; >; int main() < MyClass mc1 ; MyClass mc2 ; auto result = minimum(mc1, mc2); // Error! C2678 > 

Будет создана ошибка компилятора, так как MyClass не предоставляет перегрузку для оператора .

Не существует неотъемлемого требования к тому, чтобы аргументы типа для любого конкретного шаблона принадлежали к одной и той же иерархии объектов, хотя можно определить шаблон, который применяет такое ограничение. Объектно-ориентированные методы можно сочетать с шаблонами; Например, можно сохранить производный* в векторе. Обратите внимание, что аргументы должны быть указателями

vector vec; MyDerived d(3, L"back again", time(0)); vec.push_back(&d); // or more realistically: vector> vec2; vec2.push_back(make_shared()); 

Основные требования, которые std::vector и другие контейнеры стандартных библиотек накладывают на элементы , — это T возможности копирования T и назначения и создания с помощью копирования.

Параметры, не относящиеся к типу

В отличие от универсальных типов в других языках, таких как C# и Java, шаблоны C++ поддерживают нетиповые параметры, также называемые параметрами значений. Например, можно предоставить константное целочисленное значение, чтобы указать длину массива, как в следующем примере, аналогичном классу std::array в стандартной библиотеке:

Обратите внимание на синтаксис в объявлении шаблона. Значение size_t передается в качестве аргумента шаблона во время компиляции и должно быть const или выражением constexpr . Вы используете его следующим образом:

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

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

В Visual Studio 2017 и более поздних версиях, а также в /std:c++17 режиме или более поздней версии компилятор выводит тип аргумента шаблона, не являющегося типом, объявленного с auto помощью :

template constexpr auto constant = x; auto v1 = constant; // v1 == 5, decltype(v1) is int auto v2 = constant; // v2 == true, decltype(v2) is bool auto v3 = constant; // v3 == 'a', decltype(v3) is char 

Шаблоны в качестве параметров шаблона

Шаблон может быть параметром шаблона. В этом примере MyClass2 имеет два параметра шаблона: параметр typename T и параметр шаблона Arr:

template class Arr> class MyClass2 < T t; //OK Arra; U u; //Error. U not in scope >; 

Так как сам параметр Arr не имеет основного текста, имена его параметров не требуются. На самом деле, ссылка на имена параметров типа или класса Arr из тела MyClass2 является ошибкой. По этой причине имена параметров типа Arr можно опустить, как показано в следующем примере:

template class Arr> class MyClass2 < T t; //OK Arra; >; 

Аргументы шаблона по умолчанию

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

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

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

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

При использовании шаблона, параметры которого используются по умолчанию, используйте пустые угловые скобки:

template class Bar < //. >; . int main() < Bar<>bar; // use all default type arguments > 

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

В некоторых случаях шаблон не может или не рекомендуется определять точно такой же код для любого типа. Например, можно определить путь к коду, который будет выполняться, только если аргумент типа является указателем, std::wstring или типом, производным от определенного базового класса. В таких случаях можно определить специализацию шаблона для конкретного типа. Когда пользователь создает экземпляр шаблона с этим типом, компилятор использует специализацию для создания класса, а для всех остальных типов компилятор выбирает более общий шаблон. Специализации, в которых все параметры являются специализированными, являются полными специализациями. Если только некоторые параметры являются специализированными, это называется частичной специализацией.

template class MyMap; // partial specialization for string keys template class MyMap ; . MyMap classes; // uses original template MyMap classes2; // uses the partial specialization 

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

Дополнительные сведения см. в разделе Специализация шаблона.

Источник

Оцените статью