This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
pred(*i) != falseSection: 22.10.18.3 [func.search.bm], 22.10.18.4 [func.search.bmh], 23.2.7.1 [associative.reqmts.general], 23.3.11.5 [list.ops], 26.6.6 [alg.find], 26.6.9 [alg.find.first.of], 26.6.10 [alg.adjacent.find], 26.6.11 [alg.count], 26.6.12 [alg.mismatch], 26.6.15 [alg.search], 26.8.1 [alg.sorting.general] Status: New Submitter: Hewill Kang Opened: 2024-07-25 Last modified: 2024-08-05
Priority: 3
View other active issues in [func.search.bm].
View all other issues in [func.search.bm].
View all issues with New status.
Discussion:
The boolean-testable concept introduced in P1964R2
places appropriate constraints on boolean-ish types, so that !pred(x) or
i != last && pred(*i) always has a valid definition.
decltype(pred(*first)) should model boolean-testable.
However, boolean-testable does not guarantee that
pred(*i) != false is valid, because the type may overload operator==.
It is necessary to replace this form of expression with an appropriate one as we do in
P1964R2.
[2024-07-27; Daniel comments]
I would recommend to add a wrapping "bool(pred([…]))" and possibly
even extend to "bool(pred([…])) is true"
following our usual wording convention, since an English phrase of the form "if pred([…])"
where pred([…]) is potential non-bool and the English "if" is not a C++ language
if (with built-in conversion semantics) doesn't sound like a meaningful phrase to me.
[2024-08-02; Reflector poll]
Set priority to 3 after reflector poll. "Needs more 'is true' added".
"Would prefer not to have explicit conversions to bool unless
boolean-testable requires that.
The 'Let E be' lists don't need an 'is true' there,
but the use of 'E' should say 'is true'".
[alg.search] and [func.search.bm] have changed editorially in the draft,
the proposed resolution needs updating.
Previous resolution [SUPERSEDED]:
This wording is relative to N4986.
Modify 22.10.18.3 [func.search.bm] as indicated:
boyer_moore_searcher(RandomAccessIterator1 pat_first, RandomAccessIterator1 pat_last, Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate());-1- Preconditions: The value type of
-2- LetRandomAccessIterator1meets the Cpp17DefaultConstructible, the Cpp17CopyConstructible, and the Cpp17CopyAssignable requirements.Vbeiterator_traits<RandomAccessIterator1>::value_type. For any two valuesAandBof typeV, ifpred(A, B), then== truehf(A) == hf(B)istrue. […]-7- Returns: A pair of iterators
iandjsuch that
(7.1) —
iis the first iterator in the range [first,last - (pat_last_ - pat_first_)) such that for every non-negative integernless thanpat_last_ - pat_first_the following condition holds:pred(*(i + n), *(pat_first_ + n)), and!= false[…]
Modify 22.10.18.4 [func.search.bmh] as indicated:
boyer_moore_horspool_searcher(RandomAccessIterator1 pat_first, RandomAccessIterator1 pat_last, Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate());-1- Preconditions: The value type of
-2- LetRandomAccessIterator1meets the Cpp17DefaultConstructible, Cpp17CopyConstructible, and Cpp17CopyAssignable requirements.Vbeiterator_traits<RandomAccessIterator1>::value_type. For any two valuesAandBof typeV, ifpred(A, B), then== truehf(A) == hf(B)istrue. […]-7- Returns: A pair of iterators
iandjsuch that
(7.1) —
iis the first iterator in the range [first,last - (pat_last_ - pat_first_)) such that for every non-negative integernless thanpat_last_ - pat_first_the following condition holds:pred(*(i + n), *(pat_first_ + n)), and!= false[…]
Modify 23.2.7.1 [associative.reqmts.general] as indicated:
-3- The phrase "equivalence of keys" means the equivalence relation imposed by the comparison object. That is, two keys
[…]k1andk2are considered to be equivalent if for the comparison objectcomp,!comp(k1, k2).== false&& !comp(k2, k1)== false-177- The fundamental property of iterators of associative containers is that they iterate through the containers in the non-descending order of keys where non-descending is defined by the comparison that was used to construct them. For any two dereferenceable iterators
iandjsuch that distance fromitojis positive, the following condition holds:!value_comp(*j, *i)== false-178- For associative containers with unique keys the stronger condition holds:
value_comp(*i, *j)!= falseModify 23.3.11.5 [list.ops] as indicated:
size_type remove(const T& value); template<class Predicate> size_type remove_if(Predicate pred);-15- Effects: Erases all the elements in the list referred to by a list iterator
-16- Returns: The number of elements erased. -17- Throws: Nothing unless an exception is thrown byifor which the following conditions hold:*i == value, pred(*i). Invalidates only the iterators and references to the erased elements.!= false*i == valueorpred(*i). […]!= falseModify 26.6.6 [alg.find] as indicated:
-1- Let E be:
(1.1) —
*i == valueforfind;(1.2) —
pred(*i)for!= falsefind_if;(1.3) —
[…]!pred(*i)for== falsefind_if_not;Modify 26.6.9 [alg.find.first.of] as indicated:
-1- Let E be:
(1.1) —
*i == *jfor the overloads with no parameterpred;(1.2) —
[…]pred(*i, *j)for the overloads with a parameter!= falsepredand no parameterproj1;Modify 26.6.10 [alg.adjacent.find] as indicated:
-1- Let E be:
(1.1) —
*i == *(i + 1)for the overloads with no parameterpred;(1.2) —
[…]pred(*i, *(i + 1))for the overloads with a parameter!= falsepredand no parameterproj1;Modify 26.6.11 [alg.count] as indicated:
-1- Let E be:
(1.1) —
*i == valuefor the overloads with no parameterpredorproj;(1.2) —
[…]pred(*i)for the overloads with a parameter!= falsepredbut no parameterproj;Modify 26.6.12 [alg.mismatch] as indicated:
-2- Let E be:
(2.1) —
!(*(first1 + n) == *(first2 + n))for the overloads with no parameterpred;(2.2) —
[…]!pred(*(first1 + n), *(first2 + n))for the overloads with a parameter== falsepredand no parameterproj1;Modify 26.6.15 [alg.search] as indicated:
-1- Returns: The first iterator
[…]iin the range [first1,last1 - (last2-first2)) such that for every non-negative integernless thanlast2 - first2the following corresponding conditions hold:*(i + n) == *(first2 + n), pred(*(i + n), *(first2 + n)). Returns!= falsefirst1if [first2,last2) is empty, otherwise returnslast1if no such iterator is found.-6- Returns: The first iterator
iin the range [first,last-count) such that for every non-negative integernless thancountthe following corresponding conditions hold:*(i + n) == value, pred(*(i + n), value). Returns!= falselastif no such iterator is found.Modify 26.8.1 [alg.sorting.general] as indicated:
-3- For all algorithms that take
Compare, there is a version that usesoperator<instead. That is,comp(*i, *j)defaults to!= false*i < *j. For algorithms other than those described in 26.8.4 [alg.binary.search],!= falsecompshall induce a strict weak ordering on the values.
[2024-08-03; Daniel provides improved wording]
The current wording is inconsistent in regard to explicit conversion to bool
and lack of them in cases of expressions whose value is required to satisfy the
boolean-testable constraints. To realize consistent results for
all subclause references touched by the changes required by this issue I decided
that every E definition remains unconverted but and that every E
evaluation is interpreted as if an implied bool conversion has
been applied based on the reflector preference for that simplified approach.
bool for both expressions, because the
boolean-testable requirements do not impose a no-throw requirement for
that conversion, and they must therefore be included here.
This problem will be handled by a separate issue (LWG 4132(i)), because the
rationale for this change is different from the actual target of this issue and not
related to the other consistency adjustments done by the wording below.
Proposed resolution:
This wording is relative to N4988.
Modify 22.10.18.3 [func.search.bm] as indicated:
boyer_moore_searcher(RandomAccessIterator1 pat_first, RandomAccessIterator1 pat_last, Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate());-1- Preconditions: The value type of
-2- LetRandomAccessIterator1meets the Cpp17DefaultConstructible, Cpp17CopyConstructible, and Cpp17CopyAssignable requirements.Vbeiterator_traits<RandomAccessIterator1>::value_type. For any two valuesAandBof typeV, ifpred(A, B)is== truetrue, thenhf(A) == hf(B)istrue. […]template<class RandomAccessIterator2> pair<RandomAccessIterator2, RandomAccessIterator2> operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const;[…]
-7- Returns: A pair of iteratorsiandjsuch that
(7.1) —
iis the first iterator in the range [first,last - (pat_last_ - pat_first_)) such that for every non-negative integernless thanpat_last_ - pat_first_the following condition holds:pred(*(i + n), *(pat_first_ + n))is!= falsetrue, and(7.2) —
j == next(i, distance(pat_first_, pat_last_))istrue.
Modify 22.10.18.4 [func.search.bmh] as indicated:
boyer_moore_horspool_searcher(RandomAccessIterator1 pat_first, RandomAccessIterator1 pat_last, Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate());-1- Preconditions: The value type of
-2- LetRandomAccessIterator1meets the Cpp17DefaultConstructible, Cpp17CopyConstructible, and Cpp17CopyAssignable requirements.Vbeiterator_traits<RandomAccessIterator1>::value_type. For any two valuesAandBof typeV, ifpred(A, B), then==is truehf(A) == hf(B)istrue. […]template<class RandomAccessIterator2> pair<RandomAccessIterator2, RandomAccessIterator2> operator()(RandomAccessIterator2 first, RandomAccessIterator2 last) const;[…]
-7- Returns: A pair of iteratorsiandjsuch that
(7.1) —
iis the first iterator in the range [first,last - (pat_last_ - pat_first_)) such that for every non-negative integernless thanpat_last_ - pat_first_the following condition holds:pred(*(i + n), *(pat_first_ + n))is!= falsetrue, and(7.2) —
j == next(i, distance(pat_first_, pat_last_))istrue.
Modify 23.2.7.1 [associative.reqmts.general] as indicated:
-3- The phrase "equivalence of keys" means the equivalence relation imposed by the comparison object. That is, two keys
[…]k1andk2are considered to be equivalent if for the comparison objectcomp,!comp(k1, k2)is== false&& !comp(k2, k1)== falsetrue.-177- The fundamental property of iterators of associative containers is that they iterate through the containers in the non-descending order of keys where non-descending is defined by the comparison that was used to construct them. For any two dereferenceable iterators
iandjsuch that distance fromitojis positive, the following condition holds:
!value_comp(*j, *i)is== falsetrue.-178- For associative containers with unique keys the stronger condition holds:
value_comp(*i, *j)is!= falsetrue.
Modify 23.3.11.5 [list.ops] as indicated:
size_type remove(const T& value); template<class Predicate> size_type remove_if(Predicate pred);-15- Effects: Erases all the elements in the list referred to by a list iterator
-16- Returns: The number of elements erased. -17- Throws: Nothing unless an exception is thrown byifor which the following conditions hold:*i == valueistrue,pred(*i)is!= falsetrue. Invalidates only the iterators and references to the erased elements.*i == valueorpred(*i). […]!= false
Modify 26.6.6 [alg.find] as indicated:
[Drafting note: Sub-bullets (1.4), (1.5), and (1.6) below regarding
invokeexpressions are similarly required modelboolean-testable, as specified by conceptpredicate(18.7.4 [concept.predicate]), therefore the explicit conversion is removed here for consistency]
-1- Let E be:
(1.1) —
*i == valueforfind;(1.2) —
pred(*i)for!= falsefind_if;(1.3) —
!pred(*i)for== falsefind_if_not;(1.4) —
forbool(invoke(proj, *i) == value)ranges::find;(1.5) —
forbool(invoke(pred, invoke(proj, *i)))ranges::find_if;(1.6) —
forbool(!invoke(pred, invoke(proj, *i)))ranges::find_if_not.-2- Returns: The first iterator
iin the range[first, last)for which E istrue. Returnslastif no such iterator is found.
Modify 26.6.9 [alg.find.first.of] as indicated:
-1- Let E be:
(1.1) —
*i == *jfor the overloads with no parameterpred;(1.2) —
pred(*i, *j)for the overloads with a parameter!= falsepredand no parameterproj1;(1.3) —
for the overloads with parametersbool(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))predandproj1.[…]
-3- Returns: The first iteratoriin the range[first1, last1)such that for some iteratorjin the range[first2, last2)Eholdsistrue. Returnslast1if[first2, last2)is empty or if no such iterator is found.
Modify 26.6.10 [alg.adjacent.find] as indicated:
-1- Let E be:
(1.1) —
*i == *(i + 1)for the overloads with no parameterpred;(1.2) —
pred(*i, *(i + 1))for the overloads with a parameter!= falsepredand no parameterproj;(1.3) —
for the overloads with both parametersbool(invoke(pred, invoke(proj, *i), invoke(proj, *(i + 1))))predandproj.-2- Returns: The first iterator
isuch that bothiandi + 1are in the range[first, last)for which Eholdsistrue. Returnslastif no such iterator is found.
Modify 26.6.11 [alg.count] as indicated:
-1- Let E be:
(1.1) —
*i == valuefor the overloads with no parameterpredorproj;(1.2) —
pred(*i)for the overloads with a parameter!= falsepredbut no parameterproj;(1.3) —
invoke(proj, *i) == valuefor the overloads with a parameterprojbut no parameterpred;(1.4) —
for the overloads with both parametersbool(invoke(pred, invoke(proj, *i)))projandpred.-2- Effects: Returns the number of iterators
iin the range[first, last)for which Eholdsistrue.
Modify 26.6.12 [alg.mismatch] as indicated:
-2- Let E be:
(2.1) —
!(*(first1 + n) == *(first2 + n))for the overloads with no parameterpred;(2.2) —
!pred(*(first1 + n), *(first2 + n))for the overloads with a parameter== falsepredand no parameterproj1;(2.3) —
!invoke(pred, invoke(proj1, *(first1 + n)), invoke(proj2, *(first2 + n)))for the overloads with both parameterspredandproj1.[…]
-4- Returns:{ first1 + n, first2 + n }, wherenis the smallest integer in [0, N) such that Eholdsistrue, or N if no such integer exists.
Modify 26.6.15 [alg.search] as indicated:
-1- Returns: The first iterator
[…]iin the range [first1,last1 - (last2-first2)) such that for every non-negative integernless thanlast2 - first2the following corresponding conditions hold:*(i + n) == *(first2 + n)istrue,pred(*(i + n), *(first2 + n))is!= falsetrue. Returnsfirst1if [first2,last2) is empty, otherwise returnslast1if no such iterator is found.-6- Let E be
-7- Returns: The first iteratorpred(*(i + n), value)for the overloads with a parameter!= falsepred, and*(i + n) == valueotherwise.iin the range[first, last - count)such that for every non-negative integernless thancountthe condition E istrue. Returnslastif no such iterator is found.
Modify 26.8.1 [alg.sorting.general] as indicated:
[Drafting note: The wording below does not require extra "is
true" added to the adjusted expressions. This is comparable to the E cases above, since 26.8.1 [alg.sorting.general] p2 already points out:The return value of the function call operation applied to an object of type
Compare, when converted tobool, yieldstrueif the first argument of the call is less than the second, andfalseotherwise.]
-3- For all algorithms that take
Compare, there is a version that usesoperator<instead. That is,comp(*i, *j)defaults to!= false*i < *j. For algorithms other than those described in 26.8.4 [alg.binary.search],!= falsecompshall induce a strict weak ordering on the values.