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!
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>;
// ...
};