Home > Enterprise >  How to create a common range?
How to create a common range?

Time:09-18

Why doesn't std::ranges::common_view compile in the code below?

#include <ranges>
#include <vector>
#include <algorithm>

template <class T>
struct IteratorSentinel {};

template <class T>
class Iterator
{
public:

    using iterator_category = std::input_iterator_tag;

    using value_type = T;

    using difference_type = std::ptrdiff_t;

    using pointer = value_type*;

    using reference = value_type&;

    Iterator() = default;

    Iterator(const Iterator&) = delete;

    Iterator& operator = (const Iterator&) = delete;

    Iterator(Iterator&& other) = default;

    Iterator& operator = (Iterator&& other) = default;

    T* operator-> () { return cur(); }

    T& operator* () { return *cur(); }

    T& operator* () const { return *cur(); };

    bool operator== (const IteratorSentinel<T>&) const noexcept;

    Iterator& operator   ();

    void operator   (int);

private:

    T* cur() const
    {
        return pCur;
    }

    T* pCur = nullptr;
};

static_assert(std::input_iterator<Iterator<int>>); 

template <class T>
auto make_range()
{
    return std::ranges::subrange(Iterator<T>(), IteratorSentinel<T>{});
}

int main()
{
    auto r = make_range<int>();

    auto cr = std::ranges::common_view{ r };

    std::vector<int> v;

    std::copy(cr.begin(), cr.end(), std::back_inserter(v));

    return 0;
}

Can't figure out what template parameter does it require.

MSVC2022 error (/std:c latest):

error C2641: cannot deduce template arguments for 'std::ranges::common_view'
error C2893: Failed to specialize function template 'std::ranges::common_view<_Vw> std::ranges::common_view(_Vw) noexcept(<expr>)'

GCC12 errors:

prog.cc: In function 'int main()':
prog.cc:67:43: error: class template argument deduction failed:
   67 |     auto cr = std::ranges::common_view{ r };
      |                                           ^
prog.cc:67:43: error: no matching function for call to 'common_view(std::ranges::subrange<Iterator<int>, IteratorSentinel<int>, std::ranges::subrange_kind::unsized>&)'
In file included from prog.cc:1:
/opt/wandbox/gcc-12.1.0/include/c  /12.1.0/ranges:3724:7: note: candidate: 'template<class _Vp> common_view(_Vp)-> std::ranges::common_view<_Vp>'
 3724 |       common_view(_Vp __r)
      |       ^~~~~~~~~~~

CodePudding user response:

Your range is built out of an iterator/sentinel pair. The definition of a common range is a range where the sentinel type is an iterator. So the range itself is not a common range.

common_view can generate a common range from a non-common range. Which means that it will have to create two iterators. And since it starts the process with only one iterator, that means that, at some point, it must copy that iterator (thus creating two usable iterators).

Which it can't do because your iterator is non-copyable. Which is why common_view has an explicit requirement that the iterator is copyable.

  • Related