0

I want to create my own view using the ranges-v3 library. One should be able to pipe this view into ranges::views::transform(...) without problem, alas my current approach does not seem to allow this.

The scenario:
I have made a function that does nothing more than dereference the input and perfect-returns it, like so:

template < typename T >
decltype(auto) deref(T&& t)
{
   return std::forward< T >(t);
}

template < typename T >
   requires std::is_pointer_v< std::remove_cvref_t< T > > or other_pointer_types_like_smart_pointers...
decltype(auto) deref(T&& t)
{
      return *std::forward< T >(t);
}

Here my custom view which wraps this function:

template < ranges::range Range >
class deref_view: public ranges::view_base {
  public:
   struct iterator;
   deref_view() = default;
   deref_view(ranges::range auto&& base) : m_base(base) {}

   iterator begin() { return ranges::begin(m_base); }
   iterator end() { return ranges::end(m_base); }

  private:
   Range m_base;
};

template < ranges::range Range >
struct deref_view< Range >::iterator: ranges::iterator_t< Range > {
   using base = ranges::iterator_t< Range >;

   iterator() = default;

   iterator(const base& b) : base{b} {}

   iterator operator++(int) { return static_cast< base& >(*this)++; }

   iterator& operator++()
   {
      ++static_cast< base& >(*this);
      return (*this);
   }

   decltype(auto) operator*() const { return deref(*static_cast< base >(*this)); }
};

template < ranges::range Range >
deref_view(Range&&) -> deref_view< ranges::cpp20::views::all_t< Range > >;

struct deref_fn {
   template < typename Rng >
   auto operator()(Rng&& rng) const
   {
      return deref_view{ranges::views::all(std::forward< Rng >(rng))};
   }

   template < typename Rng >
   friend auto operator|(Rng&& rng, deref_fn const&)
   {
      return deref_view{ranges::views::all(std::forward< Rng >(rng))};
   }
};

namespace ranges::views {

constexpr deref_fn deref{};

}  

Now I am using it on a simple vector of shared pointers to int and it works fine

std::vector<std::shared_ptr<int> > vec{
   std::make_unique<int>(0),
   std::make_unique<int>(1), 
   std::make_unique<int>(2)
};

for (auto elem : vec | ranges::views::deref) {
    std::cout << elem << std::endl;
}

prints

0
1
2

But piping it into a transform fails:

for (auto elem : vec | ranges::views::deref | ranges::views::transform([](const auto& in) { return in; })) {
    std::cout << elem << std::endl;
}

As can be seen on compiler-explorer here:

https://godbolt.org/z/1KWMb34e4

Any advice on what I am doing wrong would be greatly appreciated!

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Michael A
  • 151
  • 1
  • 7

1 Answers1

0

input_iterator requires the member type alias value_type and difference_type to exist, so you need to add it to deref_view::iterator:

template <ranges::range Range>
struct deref_view<Range>::iterator : ranges::iterator_t<Range> {
    using base = ranges::iterator_t<Range>;
    using value_type = // some metaprogramming
    using difference_type = ranges::range_difference_t<Range>;
    // ...
};
康桓瑋
  • 33,481
  • 5
  • 40
  • 90
  • Thanks a lot, this was indeed missing! For anyone wondering how to fill in the value type, I did: `using value_type = std::remove_cvref_t< decltype(deref(*(std::declval< Range >().begin()))) >;` – Michael A Jun 25 '23 at 11:11