146 lines
3.6 KiB
Markdown
146 lines
3.6 KiB
Markdown
# Specialization
|
|
|
|
___
|
|
<!-- .slide: style="font-size: .7em" -->
|
|
|
|
## Function specialization
|
|
|
|
If we want to have the same function name, but we want our code to behave differently for some types, we can create a specialization.
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```cpp
|
|
//generic function
|
|
template <typename T>
|
|
void print(T arg) {
|
|
std::cout << arg << '\n';
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```cpp
|
|
// specialization for `T = double`
|
|
template <>
|
|
void print<double>(double arg) {
|
|
std::cout << std::setprecision(10) << arg << '\n';
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```cpp
|
|
// better: overload
|
|
void print(double arg) {
|
|
std::cout << std::setprecision(10) << arg << '\n';
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
Tip: do not use function specializations. Always prefer function overloads.
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
Template function specializations do not take part in overload resolution. Only the exact type match is considered.
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
Above specialization does not work for `float`. Overload does.
|
|
<!-- .element: class="fragment fade-in" -->
|
|
___
|
|
|
|
## Class specialization
|
|
|
|
A class can have not only different behaviour (different methods implementations) but also different layouts. You can have completely different fields and/or their values.
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
___
|
|
<!-- .slide: style="font-size: .8em" -->
|
|
|
|
## Specialization example #1 - methods
|
|
|
|
```c++
|
|
#include <iostream>
|
|
|
|
template<typename T> // primary template
|
|
struct is_int {
|
|
bool get() const { return false; }
|
|
};
|
|
|
|
template<> // explicit specialization for T = int
|
|
struct is_int<int> {
|
|
bool get() const { return true; }
|
|
};
|
|
|
|
|
|
int main() {
|
|
is_int<char> iic;
|
|
is_int<int> iii;
|
|
std::cout << iic.get() << '\n'; // prints 0 (false)
|
|
std::cout << iii.get() << '\n'; // prints 1 (true)
|
|
return 0;
|
|
}
|
|
```
|
|
<!-- .element: style="font-size: .65em" -->
|
|
|
|
___
|
|
<!-- .slide: style="font-size: .8em" -->
|
|
|
|
## Specialization example #2 - field values
|
|
|
|
```c++
|
|
#include <iostream>
|
|
|
|
template<typename T> // primary template
|
|
struct is_int {
|
|
static constexpr bool value = false;
|
|
};
|
|
|
|
template<> // explicit specialization for T = int
|
|
struct is_int<int> {
|
|
static constexpr bool value = true;
|
|
};
|
|
|
|
|
|
int main() {
|
|
std::cout << is_int<char>::value << '\n'; // prints 0 (false)
|
|
std::cout << is_int<int>::value << '\n'; // prints 1 (true)
|
|
return 0;
|
|
}
|
|
```
|
|
<!-- .element: style="font-size: .65em" -->
|
|
|
|
You can play with the code [here](https://ideone.com/fork/LEIx7e)
|
|
|
|
___
|
|
<!-- .slide: style="font-size: 0.85em" -->
|
|
|
|
## Specialization example #3 - <type_traits>
|
|
|
|
To achieve the last behavior, we can use `std::false_type` and `std::true_type`. The below code is equivalent to the one from the previous example.
|
|
|
|
```c++
|
|
#include <iostream>
|
|
using namespace std;
|
|
|
|
template<typename T> // primary template
|
|
struct is_int : std::false_type
|
|
{};
|
|
|
|
template<> // explicit specialization for T = int
|
|
struct is_int<int> : std::true_type
|
|
{};
|
|
|
|
int main() {
|
|
std::cout << is_int<char>::value << std::endl; // prints 0 (false)
|
|
std::cout << is_int<int>::value << std::endl; // prints 1 (true)
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
The interactive version of this code is [here](https://ideone.com/fork/GaTh0B)
|
|
|
|
___
|
|
|
|
### Exercise - `is_int_key`
|
|
|
|
In `VectorMap` write a class constant `is_int_key` that holds a boolean value. It should be `true` when the key is `int` and `false` otherwise.
|
|
|
|
Generally, it should do the same job as the `isIntKey()` method, but we want to have it available even without having an object.
|
|
|
|
Take a look in the `<type_traits>` library for that. It should be useful 🙂
|