4

I'm implementing my own version of ranges because they are not in the standard library yet. I got stuck on implementing std::iter_­difference_­t.

The latest draft says:

The type iter_­difference_­t<I> denotes

incrementable_­traits<I>​::​difference_­type if iterator_­traits<I> names a specialization generated from the primary template, and

iterator_­traits<I>​::​​difference_­type otherwise.

It seems like the obvious implementation is to have a concept for the first case and have 2nd case take everything else. But I have no idea how to transform this from English to C++. Can someone provide the code?

Community
  • 1
  • 1
  • 1
    *"my own version of ranges because they are not in the standard library yet"* Have you considered [range-v3](https://github.com/ericniebler/range-v3)? – HolyBlackCat Sep 05 '19 at 17:28
  • 2
    The first case is not implementable if you don't own `iterator_traits`. – T.C. Sep 05 '19 at 17:31

1 Answers1

3

Step 1. Be the owner of std::iterator_traits. This lets you write something in the primary like:

template <typename T>
struct iterator_traits {
    using __secret_am_i_the_primary_alias = iterator_traits;
};

Which you can check:

template <typename T>
concept is_iterator_primary = std::same_as<
    typename iterator_traits<T>::__secret_am_i_the_primary_alias,
    iterator_traits<T>>;

Step 2. Now it's pretty easy:

template <typename T>
struct iter_difference {
    using type = typename iterator_­traits<I>​::​​difference_­type;
};

template <is_iterator_primary T>
struct iter_difference<T> {
    using type = typename incrementable_­traits<I>​::​difference_­type;
};

template <typename T>
using iter_difference_t = typename iter_difference<T>::type;
Barry
  • 286,269
  • 29
  • 621
  • 977
  • 1
    Nitpick:`template using iter_difference_t = typename conditional_t, incrementable_traits, iterator_traits>::difference_type;` is a bit more compact for Step 2. – Casey Sep 06 '19 at 20:45