**Section:** 26.3.10.5 [list.ops], 26.3.9.6 [forwardlist.ops] **Status:** New
**Submitter:** Tim Song **Opened:** 2017-07-07 **Last modified:** 2017-07-12

**Priority: **3

**View all other** issues in [list.ops].

**View all issues with** New status.

**Discussion:**

There are various problems with the specification of `list::unique` and its `forward_list` counterpart, some of which are obvious even on cursory inspection:

- It refers to the identifiers
`first`and`last`, which aren't even defined. - It uses
`i - 1`on non-random-access iterators - in the case of`forward_list`, on forward-only iterators. - The resolution of LWG 202, changing the specification of
`std::unique`to require an equivalence relation and adjusting the order of comparison, weren't applied to these member functions.

LWG 491, which pointed out many of those problems with the specification of `list::unique`, was closed as NAD with the rationale that

"All implementations known to the author of this Defect Report comply with these assumption", and "no impact on current code is expected", i.e. there is no evidence of real-world confusion or harm.That implementations somehow managed to do the right thing in spite of obviously defective standardese doesn't seem like a good reason to not fix the defects.

*[2017-07 Toronto Tuesday PM issue prioritization]*

Priority 3; by the way, there's general wording in 28.3 [algorithms.requirements] p10 that lets us specify iterator arithmetic as if we were using random access iterators.

*[2017-07-11 Tim comments]*

I drafted the P/R fully aware of the general wording in 28.3 [algorithms.requirements] p10. However, that general wording is limited to Clause 28, so to make use of the shorthand permitted by that wording, we would need additional wording importing it to these subclauses.

Moreover, that general wording only defines `a+n` and `b-a`; it notably doesn't define `a-n`, which is needed here. And one cannot merely define `a-n` as
`a+(-n)` since that has undefined behavior for forward iterators.

**Proposed resolution:**

This wording is relative to N4659.

Edit 26.3.10.5 [list.ops] as indicated:

void unique(); template <class BinaryPredicate> void unique(BinaryPredicate binary_pred);

-?-

*Requires:*The comparison function shall be an equivalence relation.-19-

*Effects:*If`empty()`, has no effects. Otherwise, e~~E~~rases all but the first element from every consecutive group of~~equal~~equivalent elements referred to by the iterator`i`in the rangefor which~~[first + 1, last)~~[next(begin()), end())(for the version of~~*i == *(i-1)~~*j == *i`unique`with no arguments) or(for the version of~~pred(*i, *(i - 1))~~pred(*j, *i)`unique`with a predicate argument) holds, where`j`is an iterator in`[begin(), end())`such that`next(j) == i`. Invalidates only the iterators and references to the erased elements.-20-

*Throws:*Nothing unless an exception is thrown bythe equality comparison or the predicate.`*i == *(i-1)`or`pred(*i, *(i - 1))`-21-

*Complexity:*If~~the range~~`[first, last)`is not empty`!empty()`, exactlyapplications of the corresponding predicate, otherwise no applications of the predicate.~~(last - first) - 1~~size() - 1Edit 26.3.9.6 [forwardlist.ops] as indicated:

void unique(); template <class BinaryPredicate> void unique(BinaryPredicate binary_pred);

-?-

*Requires:*The comparison function shall be an equivalence relation.-16-

*Effects:*If`empty()`, has no effects. Otherwise, e~~E~~rases all but the first element from every consecutive group of~~equal~~equivalent elements referred to by the iterator`i`in the rangefor which~~[first + 1, last)~~[next(begin()), end())(for the version with no arguments) or~~*i == *(i-1)~~*j == *i(for the version with a predicate argument) holds, where~~pred(*i, *(i - 1))~~pred(*j, *i)`j`is an iterator in`[begin(), end())`such that`next(j) == i`. Invalidates only the iterators and references to the erased elements.-17-

*Throws:*Nothing unless an exception is thrown by the equality comparison or the predicate.-18-

*Complexity:*If~~the range~~`[first, last)`is not empty`!empty()`, exactlyapplications of the corresponding predicate, otherwise no applications of the predicate.~~(last - first) - 1~~distance(begin(), end()) - 1