Date: Wed, 28 Oct 2026 18:37:19 +0100
On Wed, 28 Oct 2026 at 10:25, Keenan Horrigan via Std-Discussion <
std-discussion_at_[hidden]> wrote:
> Hi,
>
> I was writing a version of 'std::saturating_cast' that would work with
> integer-class types as well, because I want to saturate-cast to an
> iterator's difference type, so I was reading where the standard lays out
> the rules for integer-class types:
> https://eel.is/c++draft/iterator.concept.winc
>
> In there, it's mentioned that "The width of an integer-class type is
> greater than that of every integral type of the same signedness", and I was
> wondering if the "of the same signedness" part really matters? Every
> (non-bool, non-character) integral type has a corresponding integer type of
> the opposite signedness which has the same width, and bool and the
> character types are defined in terms of signed or unsigned integer types,
> which again should come with a corresponding signed/unsigned version of the
> same width. So I'm not sure how the signedness of the integer-class type
> would affect how its width compares to integral types, which makes me worry
> that I'm missing something.
>
I don't think that the "of the same signedness" part is meaningful because
every signed integer type has a corresponding unsigned type, and these have
the same width. Integral types other than the signed integer types (e.g.
char32_t) have an unsigned integer type as their underlying type, so they
also don't cause any asymmetry.
Maybe someone was overly cautious when writing this wording; I don't see
how the signedness matters.
> It's somewhat meaningful to me, since I'm wanting to saturate-cast a
> 'std::size_t' into the iterator's difference type, and since 'std::size_t'
> is some unsigned integer type, if all integer-class types have a greater
> width than all integral types, then theoretically I wouldn't need to even
> check that the 'std::size_t' value fits into the range of the integer-class
> type, including in the case where the integer-class type is signed. Because
> if we say that 'std::size_t' has a width of 'N', then its maximum value is
> '2^N - 1', and if the integer-class type has a width of 'N + 1', then, in
> the case that it's signed, its max value would be '2^(N + 1 - 1) - 1', aka
> '2^N - 1'.
>
That is correct. If std::size_t is, say, 64-bit unsigned, the narrowest
possible integer-class type is 65-bit signed, and that can represent all
the values. There cannot be a 64-bit signed integer-class type. So I think
you're safe to assume that an integer-class type can represent all standard
and extended integer types.
However, this entire principle falls apart once P3666 and thus bit-precise
integers are introduced into the language. We have std::_Signed128 for
example, which is clearly not able to represent, say, all _BitInt(1000000)
values, and std::is_integral_v is true for bit-precise integers. Also,
integer-class types are not going away because it would break ABI.
iota_view needs to stay the same.
std-discussion_at_[hidden]> wrote:
> Hi,
>
> I was writing a version of 'std::saturating_cast' that would work with
> integer-class types as well, because I want to saturate-cast to an
> iterator's difference type, so I was reading where the standard lays out
> the rules for integer-class types:
> https://eel.is/c++draft/iterator.concept.winc
>
> In there, it's mentioned that "The width of an integer-class type is
> greater than that of every integral type of the same signedness", and I was
> wondering if the "of the same signedness" part really matters? Every
> (non-bool, non-character) integral type has a corresponding integer type of
> the opposite signedness which has the same width, and bool and the
> character types are defined in terms of signed or unsigned integer types,
> which again should come with a corresponding signed/unsigned version of the
> same width. So I'm not sure how the signedness of the integer-class type
> would affect how its width compares to integral types, which makes me worry
> that I'm missing something.
>
I don't think that the "of the same signedness" part is meaningful because
every signed integer type has a corresponding unsigned type, and these have
the same width. Integral types other than the signed integer types (e.g.
char32_t) have an unsigned integer type as their underlying type, so they
also don't cause any asymmetry.
Maybe someone was overly cautious when writing this wording; I don't see
how the signedness matters.
> It's somewhat meaningful to me, since I'm wanting to saturate-cast a
> 'std::size_t' into the iterator's difference type, and since 'std::size_t'
> is some unsigned integer type, if all integer-class types have a greater
> width than all integral types, then theoretically I wouldn't need to even
> check that the 'std::size_t' value fits into the range of the integer-class
> type, including in the case where the integer-class type is signed. Because
> if we say that 'std::size_t' has a width of 'N', then its maximum value is
> '2^N - 1', and if the integer-class type has a width of 'N + 1', then, in
> the case that it's signed, its max value would be '2^(N + 1 - 1) - 1', aka
> '2^N - 1'.
>
That is correct. If std::size_t is, say, 64-bit unsigned, the narrowest
possible integer-class type is 65-bit signed, and that can represent all
the values. There cannot be a 64-bit signed integer-class type. So I think
you're safe to assume that an integer-class type can represent all standard
and extended integer types.
However, this entire principle falls apart once P3666 and thus bit-precise
integers are introduced into the language. We have std::_Signed128 for
example, which is clearly not able to represent, say, all _BitInt(1000000)
values, and std::is_integral_v is true for bit-precise integers. Also,
integer-class types are not going away because it would break ABI.
iota_view needs to stay the same.
Received on 2026-10-28 17:37:37
