6

I'm assuming that there is a std::copy_n so that this can work with input iterators. Is there some reason why there is no std::move_n for the same reason?

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
Adrian
  • 10,246
  • 4
  • 44
  • 110
  • `std::copy_n()` works with the same types of iterators as `std::copy()`. They both take *InputIterator*s as input. The only difference is that `std::copy()` takes 2 input iterators denoting a range, whereas `std::copy_n()` takes 1 input iterator and a count. Not all situations have 2 iterators available to iterate between, sometimes a count makes more sense. – Remy Lebeau Apr 03 '19 at 19:04

2 Answers2

8

I think the answer is probably pretty mundane.

std::copy existed forever, it was the only one of these algorithms in C++03.

N1377 (2002) added move semantics into the language and also introduced the algorithms std::move() and std::move_backward() to mirror the existing std::copy() and std::copy_backward(). Those were the only copying algorithms in existence - so those were the only ones that got move versions.

N2569 (2008) added a bunch more algorithms, most of which existed in the original Standard Template Library implementation - this is where std::copy_n() and std::copy_if() came from. Since the premise of the paper was a bunch of algorithms that have been around and used for years, it couldn't have included std::move_n() or std::move_if(). It seems that this simply wasn't considered.

I'm guessing if these happened in the opposite order, we might have had std::move_n() today. But at this point, it might not be worth adding. Since, std::copy_n() isn't even used super often and move_n is very easy to implement:

template< class InputIt, class Size, class OutputIt>
OutputIt move_n(InputIt first, Size count, OutputIt result)
{
    return std::copy_n(std::make_move_iterator(first), count, result);
}
Barry
  • 286,269
  • 29
  • 621
  • 977
  • What about `std::uninitialized_move` and `std::uninitialized_move_n`? – Adrian Apr 03 '19 at 21:30
  • @Adrian [That proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0040r3.html) (2016) chose to cover both? – Barry Apr 03 '19 at 21:57
4

There is a std::make_move_iterator to adapt any iterator into providing an rvalue.

Sending an adapted input iterator to std::copy_n will achieve the desired effect, without much added noise.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 2
    Then why have the `std::move` algorithm? – Adrian Apr 03 '19 at 19:01
  • 1
    @RemyLebeau yes there is an [algorithm `std::move`](https://en.cppreference.com/w/cpp/algorithm/move) – Guillaume Racicot Apr 03 '19 at 19:05
  • 1
    Ultimately, I guess no one considered `move_n` a common enough operation to warrant a shorthand. – StoryTeller - Unslander Monica Apr 03 '19 at 19:11
  • @Adrian C++ library code has a busload of overloads and near-repetitions to make the code more expressive. It is not the reason to add definitions of course. – Euri Pinhollow Apr 03 '19 at 20:16
  • I am not sure, but there could be still a difference between `std::move[range]` (`std::move_n`) and `std::copy` (`std::copy_n`). `std::move_n` could be conventionally marked `noexcept`. `std::move[range]` is not marked `noexcept` (I don't know why) but it could. Well maybe not because, that is true only if moves are really moves (destructive) in assignment. Which one doesn't know in advance. The point is that `std::move` and `std::move_n` could be more specific at detecting the noexceptness of the move assigment, if present. – alfC Aug 22 '21 at 21:53