[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [lmi] Unexpected gcc diagnostic
From: |
Greg Chicares |
Subject: |
Re: [lmi] Unexpected gcc diagnostic |
Date: |
Sat, 10 Apr 2021 00:22:00 +0000 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.9.0 |
On 4/7/21 10:27 AM, Vadim Zeitlin wrote:
> On Wed, 7 Apr 2021 10:00:19 +0000 Greg Chicares <gchicares@sbcglobal.net>
> wrote:
>
> GC> On 4/6/21 6:59 PM, Greg Chicares wrote:
[...]
> GC> The question is when it's okay to dereference this iterator:
> GC> LowestBft = *std::min_element(Bfts.begin(), last_bft_in_test_period);
> GC> The answer is not whenever
> GC> Bfts.begin() < last_bft_in_test_period
> GC> but, rather, whenever both
> GC> Bfts.begin() < Bfts.end() [the vector is not empty], and
> GC> Bfts.begin() <= last_bft_in_test_period [the range is not insane]
>
> IMO the answer is whenever _either_
>
> Bfts.begin() < last_bft_in_test_period
>
> _or_
>
> last_bft_in_test_period < Bfts.end()
>
> I.e., by construction of last_bft_in_test_period we know that
>
> Bfts.begin() ≤ last_bft_in_test_period ≤ Bfts.end()
>
> and we need at least one of these inequalities to be strict and I would
> assert that this is true.
Agreed.
What I did in commit 79741b1ed3d17 is similar, though not
identical. The reason is that I wanted to add a !empty()
conditional before every call to std::min_element(), here
and elsewhere; and here, adding that is enough.
> GC> Maybe it's just the aftereffects of yesterday's surgery, but somehow
> GC> it troubles me to think that we have different empty sets that have
> GC> different minimums: if a≠b, then min [a,a) ≠ min [b,b) .
>
> I don't think it's correct to say that these sets have different minimums.
> min_element() returns different iterators for them, but neither of these
> iterators can be dereferenced, so the actual value of the minimum is the
> same for both empty sets: undefined/undetermined/none.
#include <algorithm>
#include <iostream>
#include <vector>
int main(int, char*[])
{
std::vector<int> v {1729};
std::cout << *std::min_element(v.begin(), v.begin()) << std::endl;
return 0;
}
That's defined to print "1729\n".
Thus, C++ ranges are not always half-open intervals. Proof:
By definition, a half-open interval is
[a,b) = {x | a ≤ x < b}
so a half-open interval with identical endpoints is empty:
[a,a) = {x | a ≤ x < a} = ∅
because a is not less than a. As you say, the minimum of
that empty interval is undefined/undetermined/none.
Assume that this
(v.begin(), v.begin())
(above) is a half-open interval. Then it has no minimum.
But its minimum is 1729.
And, if we let
std::vector<int> v2 {17};
then
(v2.begin(), v2.begin())
is the same kind of interval as above, but its minimum is 17,
by special dispensation of the Standard.
Therefore, C++ doesn't adhere strictly to the set-theoretic
definitions. It treats a range with identical endpoints
as a closed interval
[a,a]
or, following
[alg.min.max/26] ("Returns last if first == last")
exactly, as {a}.
> GC> I guess the explanation is that viewing C++ iterator ranges as
> GC> half-open is not rigorous, when I had assumed it was.
>
> I do believe it is and std::min_element() seems perfectly consistent with
> the usual C++ convention to me.
>
> Sorry if I'm still missing something here, but I just don't see what is
> the problem in all this?
I had thought C++ iterator ranges were always half-open
intervals. That's not rigorously true. The [alg.min.max/26]
behavior is reasonable, but it doesn't follow rigorously
from set theory; rather, it's just a convention, like
defining 0/0 to be zero, or one, as you please.