Tag dispatching¶
Czasami pożądane jest dostarczenie wyspecjalizowanych implementacji dla wybranej funkcji lub klasy w celu poprawy wydajności lub uniknięcia problemów.
Przykładem może być implementacja funkcji advance_iter()
, która przesuwa
iterator it
o zadaną n
ilość kroków.
Generyczna implementacja może operować na dowolnym typie iteratora:
template<typename InputIterator, typename Distance>
void advance_iter(InputIterator& x, Distance n)
{
while (n > 0)
{
++x;
--n;
}
}
Nie jest to implementacja optymalna dla iteratorów o swobodnym dostępie (np. vector<int>::iterator
).
Optymalizacja funkcji polega na utworzeniu grupy funkcji pomocniczych, które mogą być dopasowane do odpowiedniego rodzaju iteratora za pomocą „taga”, który umożliwia przeciążenie tych funkcji.
template<typename Iterator, typename Distance>
void advance_iter_impl(Iterator& x, Distance n, std::input_iterator_tag)
{
// complexity - O(N)
while (n > 0)
{
++x;
--n;
}
}
template<typename Iterator, typename Distance>
void advance_iter_impl(Iterator& x, Distance n, std::random_access_iterator_tag)
{
// complexity - O(1)
x += n;
}
Funkcja advance_iter()
po prostu przyjmuje argumenty i przekazuje je do funkcji pomocniczej. Na podstawie „taga”
odbywa się dopasowanie odpowiedniej implementacji.
template<typename Iterator, typename Distance>
void advance_iter(Iterator& x, Distance n)
{
advance_iter_impl(x, n,
typename std::iterator_traits<Iterator>::iterator_category{});
}
Klasa cech std::iterator_traits
umożliwia określenie rodzaju iteratora za pomocą typu iterator_category
.
Biblioteka standardowa definiuje zbiór typów pełniących tagujących kategorię iteratora:
namespace std
{
struct input_iterator_tag { };
struct output_iterator_tag { };
struct forward_iterator_tag : public input_iterator_tag { };
struct bidirectional_iterator_tag : public forward_iterator_tag { };
struct random_access_iterator_tag : public bidirectional_iterator_tag { };
}