C++20 : Why ranges::subrange fails for unique_ptr?

Viewed 147

I made a custom utility function for making a subrange from the given range and starting index.

It is extremely handy, but fails to work on containers with std::unique_ptr.

My code:

#include <algorithm>
#include <ranges>
#include <iostream>
#include <memory>
#include <vector>

template <std::ranges::random_access_range R>
auto range_from(R r, int t) {
    return std::ranges::subrange(std::begin(r) + t, std::end(r));
}

int main() {
    std::vector<int> v {1, 2, 3, 4};
    std::vector<std::unique_ptr<int>> u;
    u.emplace_back(std::make_unique<int>(1));
    u.emplace_back(std::make_unique<int>(2));
    u.emplace_back(std::make_unique<int>(3));
    u.emplace_back(std::make_unique<int>(4));
    
    std::vector<int> v2 (4);
    std::vector<std::unique_ptr<int>> u2 (4);

    std::ranges::copy(v | std::ranges::views::drop(2), v2.begin()); // OK    
    std::ranges::copy(range_from(v, 2), v2.begin()); // OK
    std::ranges::move(u | std::ranges::views::drop(2), u2.begin()); // OK
    // std::ranges::move(range_from(u, 2), u2.begin()); // FAIL

    
}

Why the line

    std::ranges::move(range_from(u, 2), u2.begin()); // FAIL

fails to compile? How can I resolve it? std::ranges::views::drop is too verbose.

The compiler output gives:

In file included from /opt/wandbox/gcc-head/include/c++/11.0.0/vector:66,
                 from /opt/wandbox/gcc-head/include/c++/11.0.0/functional:62,
                 from /opt/wandbox/gcc-head/include/c++/11.0.0/pstl/glue_algorithm_defs.h:13,
                 from /opt/wandbox/gcc-head/include/c++/11.0.0/algorithm:74,
                 from prog.cc:1:
/opt/wandbox/gcc-head/include/c++/11.0.0/bits/stl_uninitialized.h: In instantiation of '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*]':
/opt/wandbox/gcc-head/include/c++/11.0.0/bits/stl_uninitialized.h:332:37:   required from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<int>*, std::vector<std::unique_ptr<int> > >; _ForwardIterator = std::unique_ptr<int>*; _Tp = std::unique_ptr<int>]'
/opt/wandbox/gcc-head/include/c++/11.0.0/bits/stl_vector.h:558:31:   required from 'std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<int>; _Alloc = std::allocator<std::unique_ptr<int> >]'
prog.cc:25:38:   required from here
/opt/wandbox/gcc-head/include/c++/11.0.0/bits/stl_uninitialized.h:137:72: error: static assertion failed: result type must be constructible from value type of input range
  137 |       static_assert(is_constructible<_ValueType2, decltype(*__first)>::value,
      |  

Oh, this workaround also fails:

// ...
template <std::ranges::random_access_range R>
auto range_from2(R r, int t) {
    return r | std::ranges::views::drop(t);
}

int main() {
// ...
    std::ranges::move(range_from2(u, 2), u2.begin()); // FAIL   
}
0 Answers
Related