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 { };
}