lundi 2 janvier 2017

Template class specialization vs function overloading

The title is not the best so let me explain: I'm experimenting with a custom mini-stl (for learning purposes) and currently implementing the std::distance function. The function must behave differently for random access iterators and simple input iterators.

Function overloading

Both std (in Microsoft's implementation) and EASTL use operator overloading to select the appropriate function, something like this:

namespace internal
{
    template <typename Iter>
    inline typename IteratorTraits<Iter>::DifferenceType DistanceImpl(Iter first, Iter last, InputIteratorTag)
    {
        // ...
    }

    template <typename Iter>
    inline typename IteratorTraits<Iter>::DifferenceType DistanceImpl(Iter first, Iter last, RandomAccessIteratorTag)
    {
        // ...
    }
}

template <typename Iter>
inline typename IteratorTraits<Iter>::DifferenceType Distance(Iter first, Iter last)
{
    // the last parameter of the function selects the proper DistanceImpl
    return internal::DistanceImpl<Iter>(first, last, (typename IteratorTraits<Iter>::IteratorCategory)());
}

I guess the temporary object (the category tag parameter which is an empty struct) will be optimized away since it's not used.

Class specialization with static function

What's about the specialization of a helper class with a static function?

namespace internal
{
    template <typename Cat>
    struct DistanceImpl;

    template <>
    struct DistanceImpl<InputIteratorTag>
    {
        template <typename Iter>
        inline static typename IteratorTraits<Iter>::DifferenceType Calc(Iter first, Iter last)
        {
            // ...
        }
    };

    template <>
    struct DistanceImpl<RandomAccessIteratorTag>
    {
        template <typename Iter>
        inline static typename IteratorTraits<Iter>::DifferenceType Calc(Iter first, Iter last)
        {
            // ...
        }
    };
}

template <typename Iter>
inline typename IteratorTraits<Iter>::DifferenceType Distance(Iter first, Iter last)
{
    return internal::DistanceImpl<typename IteratorTraits<Iter>::IteratorCategory>::Calc<Iter>(first, last);
}

Questions

  • Difference(s) between the two solution? (Including performance and reliability)
  • Advantages/Disadvantages?

Aucun commentaire:

Enregistrer un commentaire