#include <vector>
#include <iostream>
#include <range/v3/all.hpp>
int main()
{
auto coll = std::vector{ 1, 2, 3 };
ranges::copy(
coll,
ranges::ostream_iterator<int>{ std::cout, ", " }
); // ok
ranges::copy(
coll,
std::ostream_iterator<int>{ std::cout, ", " }
); // error
}
The issue is shown in the code above. I use ranges-v3-0.3.7.
To me, the generic algorithm copy
shouldn't care about the destination iterator type as long as it meets the requirements of output iterator.
If so, why aren't ranges' algorithms compatible with std's iterators?
This is correct. It's not that
ranges::copy
somehow recognizesranges::ostream_iterator
and notstd::ostream_iterator
. It's that Ranges has a refined concept for what an OutputIterator† is, such thatranges::ostream_iterator
does model OutputIterator butstd::ostream_iterator
does not.Specifically,
ranges::copy()
requiresWeaklyIncrementable<O>
which refinesSemiRegular<O>
which requiresDefaultConstructible
.ranges::ostream_iterator
is default constructible, butstd::ostream_iterator
is not.Hence the failure.
In P0896, the range-based
copy()
algorithm does requireWeaklyIncrementable
(and thusDefaultConstructible
) for its output iterator - but addresses this mismatch by also adding a default constructor tostd::ostream_iterator
(see page 70).† 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 usingstd::copy
with astd::ostream_iterator
today is perfectly fine. And post-P0896, usingranges::copy
with astd::ostream_iterator
will also be fine - because of the proposed changes tostd::ostream_iterator
.