pred(*i) != false
Section: 22.10.18.3 [func.search.bm], 22.10.18.4 [func.search.bmh], 23.2.7.1 [associative.reqmts.general], 23.3.9.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 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- LetRandomAccessIterator1
meets the Cpp17DefaultConstructible, the Cpp17CopyConstructible, and the Cpp17CopyAssignable requirements.V
beiterator_traits<RandomAccessIterator1>::value_type
. For any two valuesA
andB
of typeV
, ifpred(A, B)
, then== truehf(A) == hf(B)
istrue
. […]-7- Returns: A pair of iterators
i
andj
such that
(7.1) —
i
is the first iterator in the range [first
,last - (pat_last_ - pat_first_)
) such that for every non-negative integern
less 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- LetRandomAccessIterator1
meets the Cpp17DefaultConstructible, Cpp17CopyConstructible, and Cpp17CopyAssignable requirements.V
beiterator_traits<RandomAccessIterator1>::value_type
. For any two valuesA
andB
of typeV
, ifpred(A, B)
, then== truehf(A) == hf(B)
istrue
. […]-7- Returns: A pair of iterators
i
andj
such that
(7.1) —
i
is the first iterator in the range [first
,last - (pat_last_ - pat_first_)
) such that for every non-negative integern
less 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
[…]k1
andk2
are 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
i
andj
such that distance fromi
toj
is 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.9.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 byi
for which the following conditions hold:*i == value, pred(*i)
. Invalidates only the iterators and references to the erased elements.!= false*i == value
orpred(*i)
. […]!= falseModify 26.6.6 [alg.find] as indicated:
-1- Let E be:
(1.1) —
*i == value
forfind
;(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 == *j
for the overloads with no parameterpred
;(1.2) —
[…]pred(*i, *j)
for the overloads with a parameter!= falsepred
and 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!= falsepred
and no parameterproj1
;Modify 26.6.11 [alg.count] as indicated:
-1- Let E be:
(1.1) —
*i == value
for the overloads with no parameterpred
orproj
;(1.2) —
[…]pred(*i)
for the overloads with a parameter!= falsepred
but 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== falsepred
and no parameterproj1
;Modify 26.6.15 [alg.search] as indicated:
-1- Returns: The first iterator
[…]i
in the range [first1
,last1 - (last2-first2)
) such that for every non-negative integern
less thanlast2 - first2
the following corresponding conditions hold:*(i + n) == *(first2 + n), pred(*(i + n), *(first2 + n))
. Returns!= falsefirst1
if [first2
,last2
) is empty, otherwise returnslast1
if no such iterator is found.-6- Returns: The first iterator
i
in the range [first
,last-count
) such that for every non-negative integern
less thancount
the following corresponding conditions hold:*(i + n) == value, pred(*(i + n), value)
. Returns!= falselast
if 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],!= falsecomp
shall 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), 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- LetRandomAccessIterator1
meets the Cpp17DefaultConstructible, Cpp17CopyConstructible, and Cpp17CopyAssignable requirements.V
beiterator_traits<RandomAccessIterator1>::value_type
. For any two valuesA
andB
of 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 iteratorsi
andj
such that
(7.1) —
i
is the first iterator in the range [first
,last - (pat_last_ - pat_first_)
) such that for every non-negative integern
less 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- LetRandomAccessIterator1
meets the Cpp17DefaultConstructible, Cpp17CopyConstructible, and Cpp17CopyAssignable requirements.V
beiterator_traits<RandomAccessIterator1>::value_type
. For any two valuesA
andB
of 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 iteratorsi
andj
such that
(7.1) —
i
is the first iterator in the range [first
,last - (pat_last_ - pat_first_)
) such that for every non-negative integern
less 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
[…]k1
andk2
are 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
i
andj
such that distance fromi
toj
is 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.9.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 byi
for which the following conditions hold:*i == value
istrue
,pred(*i)
is!= falsetrue
. Invalidates only the iterators and references to the erased elements.*i == value
orpred(*i)
. […]!= false
Modify 26.6.6 [alg.find] as indicated:
[Drafting note: Sub-bullets (1.4), (1.5), and (1.6) below regarding
invoke
expressions 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 == value
forfind
;(1.2) —
pred(*i)
for!= falsefind_if
;(1.3) —
!pred(*i)
for== falsefind_if_not
;(1.4) —
for
bool(invoke(proj, *i) == value)ranges::find
;(1.5) —
for
bool(invoke(pred, invoke(proj, *i)))ranges::find_if
;(1.6) —
for
bool(!invoke(pred, invoke(proj, *i)))ranges::find_if_not
.-2- Returns: The first iterator
i
in the range[first, last)
for which E istrue
. Returnslast
if no such iterator is found.
Modify 26.6.9 [alg.find.first.of] as indicated:
-1- Let E be:
(1.1) —
*i == *j
for the overloads with no parameterpred
;(1.2) —
pred(*i, *j)
for the overloads with a parameter!= falsepred
and no parameterproj1
;(1.3) —
for the overloads with parameters
bool(invoke(pred, invoke(proj1, *i), invoke(proj2, *j)))pred
andproj1
.[…]
-3- Returns: The first iteratori
in the range[first1, last1)
such that for some iteratorj
in the range[first2, last2)
Eholdsistrue
. Returnslast1
if[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!= falsepred
and no parameterproj
;(1.3) —
for the overloads with both parameters
bool(invoke(pred, invoke(proj, *i), invoke(proj, *(i + 1))))pred
andproj
.-2- Returns: The first iterator
i
such that bothi
andi + 1
are in the range[first, last)
for which Eholdsistrue
. Returnslast
if no such iterator is found.
Modify 26.6.11 [alg.count] as indicated:
-1- Let E be:
(1.1) —
*i == value
for the overloads with no parameterpred
orproj
;(1.2) —
pred(*i)
for the overloads with a parameter!= falsepred
but no parameterproj
;(1.3) —
invoke(proj, *i) == value
for the overloads with a parameterproj
but no parameterpred
;(1.4) —
for the overloads with both parameters
bool(invoke(pred, invoke(proj, *i)))proj
andpred
.-2- Effects: Returns the number of iterators
i
in 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== falsepred
and no parameterproj1
;(2.3) —
!invoke(pred, invoke(proj1, *(first1 + n)), invoke(proj2, *(first2 + n)))
for the overloads with both parameterspred
andproj1
.[…]
-4- Returns:{ first1 + n, first2 + n }
, wheren
is 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
[…]i
in the range [first1
,last1 - (last2-first2)
) such that for every non-negative integern
less thanlast2 - first2
the following corresponding conditions hold:*(i + n) == *(first2 + n)
istrue
,pred(*(i + n), *(first2 + n))
is!= falsetrue
. Returnsfirst1
if [first2
,last2
) is empty, otherwise returnslast1
if 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) == value
otherwise.i
in the range[first, last - count)
such that for every non-negative integern
less thancount
the condition E istrue
. Returnslast
if 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
, yieldstrue
if the first argument of the call is less than the second, andfalse
otherwise.]
-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],!= falsecomp
shall induce a strict weak ordering on the values.