To me, the generic algorithm copy
shouldn't care about the destination iterator type as long as it meets the requirements of output iterator.
This is correct. It's not that ranges::copy
somehow recognizes ranges::ostream_iterator
and not std::ostream_iterator
. It's that Ranges has a refined concept for what an OutputIterator† is, such that ranges::ostream_iterator
does model OutputIterator but std::ostream_iterator
does not.
Specifically, ranges::copy()
requires WeaklyIncrementable<O>
which refines SemiRegular<O>
which requires DefaultConstructible
. ranges::ostream_iterator
is default constructible, but std::ostream_iterator
is not.
Hence the failure.
In P0896, the range-based copy()
algorithm does require WeaklyIncrementable
(and thus DefaultConstructible
) for its output iterator - but addresses this mismatch by also adding a default constructor to std::ostream_iterator
(see page 70).
As an update to this, P2325R3 was just adopted retroactively for C++20, which reverts this change. std::ostream_iterator
will no longer be default constructible and the weakly_incrementable
concept will no longer require default constructibility (among other changes).
† Note that the range-v3/Ranges TS/Ranges Proposal concept OutputIterator is separate from the standard library's existing concept of OutputIterator. std::ostream_iterator
does not model the former but it does model the latter - so using std::copy
with a std::ostream_iterator
today is perfectly fine. And post-P0896, using ranges::copy
with a std::ostream_iterator
will also be fine - because of the proposed changes to std::ostream_iterator
.
std::ostream_iterator
is designed without any support of ranges. The point is demonstrating feasibility of formally introducing such support to a future standard, not locking down a complete specification.Presumably, if ranges is introduced into a future version of the standard, the specification forranges::ostream_iterator
will become part of the specification forstd::ostream_iterator
, andranges::copy()
will become part of the specification ofstd::copy()
, and any incompatibilities will be addressed. – Cottonranges::copy
requires its output iterator be default constructible. Andranges::copy
will stayranges::copy
(std::ranges::copy
, to be precise) and not be merged withstd::copy
. See Barry's answer below for the low down. – Poffranges::copy
need to default-construct its output iterator? (Why?) If not, this seems like a needless incompatibility... – Mccullochstd::ostream_iterator
is default constructible, which means from the discussions, that it would work. – Sibship