unique_copy()
sometimes can't fall back to reading its outputSection: 26.7.9 [alg.unique] Status: C++17 Submitter: Stephan T. Lavavej Opened: 2014-10-01 Last modified: 2017-07-30
Priority: 3
View all other issues in [alg.unique].
View all issues with C++17 status.
Discussion:
unique_copy()
's wording says that if it's given input-only and output-only iterators, it needs
the input's value type to be copyable. This is correct, because in this case the algorithm must have a
local element copy in order to detect duplicates.
InputIterator
that's forward or stronger, the input's
value type doesn't have to be copyable. This is also correct, because in this case the algorithm can reread
the input in order to detect duplicates.
Finally, the wording says that if it's given an input-only iterator with an OutputIterator
that's
forward or stronger, the input's value type doesn't have to be copyable. This is telling the algorithm to
compare its input to its output in order to detect duplicates, but that isn't always possible! If the input
and output have the same value type, then they can be compared (as long as *result = *first
behaves
sanely; see below). If they have different value types, then we can't compare them.
This could be resolved by requiring heterogeneous value types to be comparable in this situation, but that
would be extremely tricky to wordsmith (as it would challenge the concept of "group of equal elements" used
by the Effects). It will be vastly simpler and more effective to extend the "local element copy" requirement
to this scenario.
Note that the input-only, output forward-or-stronger, identical value types scenario needs a bit of work too.
We always require *result = *first to be "valid", but in this case we need to additionally require that the
assignment actually transfers the value. (Otherwise, we'd be allowing an op=()
that ignores *first
and always sets *result
to zero, or other unacceptable behavior.) This is just CopyAssignable
.
(What happens when unique_copy()
is given a move_iterator
is a separate issue.)
To summarize:
input forward+: no additional requirements
input-only, output forward+, same value types: needsCopyAssignable
input-only, output forward+, different value types: needsCopyConstructible
andCopyAssignable
input-only, output-only: needsCopyConstructible
andCopyAssignable
[Urbana 2014-11-07: Move to Ready]
Proposed resolution:
This wording is relative to N3936.
Change 26.7.9 [alg.unique] p5, as depicted:
template<class InputIterator, class OutputIterator> OutputIterator unique_copy(InputIterator first, InputIterator last, OutputIterator result); template<class InputIterator, class OutputIterator, class BinaryPredicate> OutputIterator unique_copy(InputIterator first, InputIterator last, OutputIterator result, BinaryPredicate pred);-5- Requires: The comparison function shall be an equivalence relation. The ranges [
first,last
) and [result,result+(last-first)
) shall not overlap. The expression*result = *first
shall be valid.If neitherLetInputIterator
norOutputIterator
meets the requirements of forward iterator then the value type ofInputIterator
shall beCopyConstructible
(Table 21) andCopyAssignable
(Table 23). OtherwiseCopyConstructible
is not required.T
be the value type ofInputIterator
. IfInputIterator
meets the forward iterator requirements, then there are no additional requirements forT
. Otherwise, ifOutputIterator
meets the forward iterator requirements and its value type is the same asT
, thenT
shall beCopyAssignable
(Table 23). Otherwise,T
shall be bothCopyConstructible
(Table 21) andCopyAssignable
.