3

I have the following code where for some reason only last block does not work.

I originally thought it may be related to unique_ptr being move only or std::set having const keys, but then it is unclear why other blocks work.

 namespace sr = std::ranges; namespace sv = std::views; int main() { { std::set<int> up_s{10,20}; const auto up_vec = sv::as_rvalue(up_s) | sr::to<std::vector>(); assert(up_vec.size() == 2); } { std::vector<std::unique_ptr<int>> up_d; up_d.emplace_back(std::make_unique<int>(10)); up_d.emplace_back(std::make_unique<int>(20)); const auto up_vec = sv::as_rvalue(up_d) | sr::to<std::vector>(); assert(up_vec.size() == 2); } { std::set<std::unique_ptr<int>> up_d; up_d.emplace(std::make_unique<int>(10)); up_d.emplace(std::make_unique<int>(20)); //const auto up_vec = sv::as_rvalue(up_d) | sr::to<std::vector>(); //assert(up_vec.size() == 2); } } 

Error message seems useless, as it looks like that for some reason code wants to treat unique_ptr as range

/opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/ranges:9354:25: error: static assertion failed 9354 | static_assert(input_range<range_reference_t<_Rg>>); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/ranges:9354:25: note: constraints not satisfied

...

/opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/bits/ranges_base.h:499:13: required for the satisfaction of 'range<_Tp>' [with _Tp = const std::unique_ptr<int, std::default_delete >&&] /opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/bits/ranges_base.h:499:21: in requirements with '_Tp& __t' [with _Tp = const std::unique_ptr<int, std::default_delete >&&] /opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/bits/ranges_base.h:501:22: note: the required expression 'std::ranges::_Cpo::begin(__t)' is invalid 501 | ranges::begin(__t); | ~~~~~~~~~~~~~^~~~~ /opt/compiler-explorer/gcc-trunk-20240513/include/c++/15.0.0/bits/ranges_base.h:502:20: note: the required expression 'std::ranges::_Cpo::end(__t)' is invalid 502 | ranges::end(__t);

1 Answer 1

5

I originally thought it may be related to unique_ptr being move only or std::set having const keys, but then it is unclear why other blocks work.

You've hit the nail on the head. It's very difficult to tell from the errors and I wasn't able to produce some error message that would make it obvious, but in short, the issue is that std::set only gives us access to const keys and std::unique_ptr would require something non-const to make moving possible.

Piping this range through as_rvalue doesn't fix this problem; it just means that we're working with a range of xvalues of type const std::unique_ptr, but that's no good. The following code is ill-formed, and so is your attempt at making a vector:

const std::unique_ptr<int> p; auto q = std::move(p); // call to deleted copy constructor, ill-formed 

To get more into specifics, ranges::to<std::vector> would require std::vector(std::from_range, sv::as_rvalue(up_d)) to be valid. However, the constraint container-compatible-range is not satisfied because const std::unique_ptr<int>&& is not convertible to std::unique_ptr<int>.

Other cases

In the case of std::set<int>, the constness doesn't matter. std::set<int> is range of const int lvalues, and piping it through as_rvalue makes it a range of const int xvalues. The following code is fine, and so is construction of a std::vector<int> from such a range:

const int x = 0; int y = std::move(x); // initialization of an int from an xvalue of type const int 

In the case of std::vector<std::unique_ptr<int>>, constness isn't a problem. A std::vector gives us non-const access to the elements, so piping it through as_rvalue gives us a range of non-const std::unique_ptr xvalues. Therefore, the move constructor will be called for each element.

Sign up to request clarification or add additional context in comments.

1 Comment

ah yes, thank you... tbh kind of disappointing that code with set<int> compiles, I mean I now understand why it works, but I would hope that as_rvalue would refuse to operate on const elements... example to show that elements are obviously not moved godbolt.org/z/dPTxjr16Y

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.