6.7 KiB
Template functions
Examples
Let's assume that we have a function below:
int add(int first, int second) {
return first + second;
}
If we want to have a function that takes doubles as well, we need to write:
double add(double first, double second) {
return first + second;
}
And if we want a function that can take complex or any other numbers we would need to write:
std::complex<int> add(std::complex<int> first, std::complex<int> second) {
return first + second;
}
You can clearly see that we have a code duplication here.
Avoiding code duplication
Instead of writing so many functions we can have only one - template function:
template <typename Type>
Type add(Type first, Type second) {
return first + second;
}
Instead of Type, you can have any name you wish. Typically you will see just T as a typename, but it is better to have a longer name than only one character, especially, when there is more than only one template parameter. Now, you can use this function like this:
auto resultI = add<int>(4, 5); // resultI type is int
auto resultD = add<double>(4.0, 5.0); // resultD type is double
auto resultC = add<std::complex<int>>({1, 2}, {2, 3}); // resultC type is std::complex<int>
You can play with the code here
Function template type deduction
There is a function template types deduction in C++. It means that you can skip part with angle braces <> and write previous example like this:
auto resultI = add(4, 5); // resultI type is int
auto resultD = add(4.0, 5.0); // resultD type is double
auto resultC = add({1, 2}, {2, 3}); // error, does not compile
resultC will not compile, because in this case compiler will not know what is the type of {1, 2} or {2, 3}. std::initializer_list can never be a result of parameter type deduction in templates.
In this case we have to type it explicitly:
auto resultC = add(std::complex<int>{1, 2}, std::complex<int>{2, 3});
or
auto resultC = add<std::complex<int>>({1, 2}, {2, 3});
Exercise
Write a function that creates std::complex number from two provided numbers. If the types of numbers are different, it should create std::complex of the first parameter. Usage:
std::complex<int> a = makeComplex(4, 5); // both ints
std::complex<double> b = makeComplex(3.0, 2.0); // both doubles
std::complex<int> c = makeComplex(1, 5.0); // int, double -> takes int
Multiple template parameters
The compiler itself deduce which template function parameters should be used. However, if you write the code like this:
auto resultC = add(4, 5.0); // error: int + double
We will have a compilation error. The compiler will not deduce parameter, because our template function takes only one type, and both parameters have to be of the same type. We can fix this by adding a new version of the template of add function.
template <typename TypeA, typename TypeB>
TypeA add(TypeA first, TypeB second) {
return first + second;
}
Now the code should work:
auto resultC = add(4, 5.0); // resultC type is int
The output type is the same as the first argument type because it was defined in the template function above as TypeA.
typeid
Generally, you can freely use template types inside functions. For example, you can create new variables of provided types:
#include <typeinfo>
template <class T>
void showType() {
T value;
std::cout << "Type: " << typeid(value).name() << std::endl;
}
You can use typeid().name() to print variable type. You need to include the typeinfo header for this. The output is implementation-defined.
You can also notice, that instead of the typename keyword, you can also use the class keyword. They are interchangeable.
template <typename T> == template <class T> != template <struct T>
No matching function
In previous case if you want to use showType() function without providing explicit templates, the code will not compile:
int main() {
showType();
return 0;
}
prog.cpp: In function ‘int main()’:
prog.cpp:15:12: error: no matching function for call to showType()’
showType();
^
prog.cpp:7:6: note: candidate: template<class T> void showType()
void showType()
^~~~~~~~~
prog.cpp:7:6: note: template argument deduction/substitution failed:
prog.cpp:15:12: note: couldn't deduce template parameter ‘T’
showType();
Template function parameter type deduction
The compiler cannot deduce parameters, because the functions do not take any parameters. You need to provide the type explicitly:
int main() {
showType<int>();
return 0;
}
or
int main() {
showType<std::vector<char>>();
return 0;
}
You can also play with the code here
STL example
template<class InputIt, class UnaryPredicate>
InputIt find_if(InputIt first, InputIt last, UnaryPredicate p)
{
for(; first != last; ++first) {
if(p(*first)) {
return first;
}
}
return last;
}
std::vector<std::pair<int, int>> v{{-3, 1}, {2, 3}, {4, -5}};
auto it = std::find_if(begin(v), end(v), [](auto& e){ return e.first == 2; });
if(it != std::end(v)) {
/* ... */
}