最終更新日時: 2026年02月24日 23時01分12秒 (JST)
yoh が更新

履歴 編集

variable
<iterator>

# std::is-integer-like(C++20)

    namespace std {
      template<class T>
      inline constexpr bool is-integer-like = see below;

      template<class T>
      inline constexpr bool is-signed-integer-like = see below;
    }

## 概要

これらの説明専用の変数テンプレートは、任意の型`T`が符号付/なし整数型そのものあるいはそれと同様に扱える型である場合に`true`を示すものである。

これは標準ライブラリ内において、イテレータの差分型（`difference_type`）として実装定義の整数型の使用を許可するためにコンセプトの文脈で使用される。

## 効果

`is-integer-like<T>`は`T`が`integral`のモデルとなるかinteger-classである時に`true`を示す。ただし、`T`が`bool`かそのCV修飾された型である場合は常に`false`となる。
`is-signed-integer-like<T>`は`T`が`integer-like`（`is-integer-like<T> == true`）であり、`signed_integral`のモデルとなるかsigned-integer-classである時に`true`を示す。

## (signed-)integer-class型

integer-class型は組み込みの整数型と同じように動作する実装定義の型である。integer-class型は必ずしもクラス型であるとは限らない。

integer-class型は2の補数で値を表現し、その幅は同じ符号の全ての組み込み整数型よりも大きい。

integer-class型の表現可能な範囲はそれが定義する値の連続集合であり、`0`と`1`を必ず含んでいなければならない。この時、その範囲に負の数が含まれていればその型はsigned-integer-class型であり、それ以外のものはunsigned-integer-class型である。

### 要件

`I`をあるinteger-class型、`B`を少なくとも`I`と同じ範囲の値を表現可能で同じ幅を持つ別のinteger-class型とする。 `I`の値`a, b`、`a, b`それぞれと同じ値を表現する`B`の値`x, y`と任意の整数型の値`c`について次のことが成り立つ。

- 式`@x`が適格である全ての単項演算子`@`について`@a`もまた適格であり、共に同じ値、効果、値カテゴリを持つ。`@x`が`bool`型を示す場合`@a`もまた`bool`型を示すが。`@x`が`B`を示す場合は`@a`は`I`を示す。
- 式`c @= x`が適格である全ての（複合）代入演算子`@=`について`c @= a`もまた適格であり、共に同じ値、効果を持つ。式`c @= a`の結果は`c`を参照するlvalueとなる。
- 式`x @ y`が適格である全ての二項演算子`@`について`a @ b`もまた適格であり、結果の値を`I`が表現できる場合は共に同じ値、効果、値カテゴリを持つ。`x @ y`が`bool`型を示す場合`a @ b`もまた`bool`型を示すが。`x @ y`が`B`を示す場合は`a @ b`は`I`を示す。
- integer-class型の値は任意の整数型に明示的に変換でき、任意の整数型の値はinteger-class型に暗黙的にも明示的にも変換できる。それらの変換は例外を送出しない。
- integer-class型の式`E`は`bool(E != I(0))`のように文脈的に`bool`に変換できる。
- integer-class型は`regular`及び`totally_ordered`のモデルとなる。
- 値初期化されたinteger-class型の値は`0`になる。

### integer-class型間の変換

integer-class型`I1`からinteger-class型`I2`への変換について：

- `I1`と`I2`が同じ符号を持ち、`I2`の幅が`I1`の幅以上である場合、`I1`の値は`I2`へ暗黙的にも明示的にも変換可能である
- それ以外の場合、`I1`の値は`I2`へ明示的に変換可能である

### common_type

任意の2つのinteger-like型`I1`と`I2`について、`common_type_t<I1, I2>`は`I1`と`I2`のどちらの幅以上の幅を持つinteger-class型を示す。

### numeric_limits

integer-class型`I`について`numeric_limits<I>`の特殊化は次のような値を示す。

- `numeric_limits<I>::is_specialized == true`
- `numeric_limits<I>::is_signed == true`
  - `I`がsigned-integer-class型の場合のみ
- `numeric_limits<I>::digits`は`I`の幅と等しい
- `numeric_limits<I>::digits10`は`static_cast<int>(digits * log10(2))`と等しい
- `numeric_limits<I>::min()`と`numeric_limits<I>::max()`はそれぞれ、`I`の表現可能な値の最小値と最大値を返す。`numeric_limits<I>::lowest()`は`numeric_limits<I>::max()`を返す。

## 実装例 (MSVC)

    inline constexpr bool _Is_nonbool_integral = is_integral_v<_Ty> && !is_same_v<remove_cv_t<_Ty>, bool>;

    template <class _Ty>
    inline constexpr bool _Integer_class = requires {
      typename _Ty::_Signed_type;
      typename _Ty::_Unsigned_type;
    };

    template <class _Ty>
    concept _Integer_like = _Is_nonbool_integral<remove_cv_t<_Ty>> || _Integer_class<_Ty>;

    template <class _Ty>
    concept _Signed_integer_like = _Integer_like<_Ty> && static_cast<_Ty>(-1) < static_cast<_Ty>(0);

上記の説明のうち構文的な要件を素直に実装している。MSVCでは、128ビット整数がinteger-class型である。

## バージョン

### 言語

- C++20

## 関連項目

- `weakly_incrementable`
- `iota_view`

## 参照

- P1522R1 Iterator Difference Type and Integer Overflow
- P2393R1 Cleaning up integer-class types
- LWG Issue 3467. bool can't be an integer-like type