# Template functions ___ ## Examples Let's assume that we have a function below: ```c++ 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: ```c++ 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: ```c++ std::complex add(std::complex first, std::complex 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: ```c++ template 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: ```c++ 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}); // resultC type is std::complex ``` You can play with the code [here](https://ideone.com/fork/NU0L8k) ___ ## 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: ```c++ 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: ```c++ auto resultC = add(std::complex{1, 2}, std::complex{2, 3}); ``` or ```c++ auto resultC = add>({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: ```c++ std::complex a = makeComplex(4, 5); // both ints std::complex b = makeComplex(3.0, 2.0); // both doubles std::complex 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: ```c++ 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. ```c++ template TypeA add(TypeA first, TypeB second) { return first + second; } ``` Now the code should work: ```c++ 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: ```cpp #include template 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. ```cpp template == template != template ``` ___ ## No matching function In previous case if you want to use `showType()` function without providing explicit templates, the code will not compile: ```c++ int main() { showType(); return 0; } ``` ```bash 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 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:
```c++ int main() { showType(); return 0; } ```
or
```c++ int main() { showType>(); return 0; } ```
You can also play with the code [here](https://ideone.com/fork/oZZybw) ___ ## STL example ```cpp template InputIt find_if(InputIt first, InputIt last, UnaryPredicate p) { for(; first != last; ++first) { if(p(*first)) { return first; } } return last; } ``` ```cpp std::vector> 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)) { /* ... */ } ```