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(), 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(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_impl(Iterator& x, Distance n, std::input_iterator_tag)
{
// complexity - O(N)
while (n > 0)
{
++x;
--n;
}
}
template<typename Iterator, typename Distance>
void advance_impl(Iterator& x, Distance n, std::random_access_iterator_tag)
{
// complexity - O(1)
x += n;
}
Funkcja advance() 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(Iterator& x, Distance n)
{
advance_impl(x, n,
typename std::iterator_traits<Iterator>::iterator_category{});
}
Cechy iteratorów#
Klasa cech std::iterator_traits umożliwia dostęp do informacji o iteratorze, takich jak:
typ elementu, na który wskazuje iterator -
std::iterator_traits<Iterator>::value_typekategoria iteratora -
std::iterator_traits<Iterator>::iterator_category
std::vector<int> vec;
using Iterator = std::vector<int>::iterator;
static_assert(std::is_same_v<std::iterator_traits<Iterator>::value_type, int>);
Biblioteka standardowa definiuje zbiór typów opisują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 { };
}
static_assert(
std::is_same_v
<
std::iterator_traits<Iterator>::iterator_category,
std::random_access_iterator_tag
>
);