最終更新日時: 2026年03月13日 11時25分45秒 (JST)
Akira Takahashi が更新

履歴 編集

class template
<flat_map>

# std::flat_map(C++23)

    namespace std {
      template <class Key,
                class T,
                class Compare = less<Key>,
                class KeyContainer = vector<Key>,
                class MappedContainer = vector<T>>
      class flat_map;
    }

## 概要

`std::flat_map`は、重複しない要素を格納する連想コンテナの一種であり、キーとそれに対応する値を格納する。

`std::flat_map`は、ノードベースで実装される`std::map`、ハッシュテーブルで実装される`std::unordered_map`とは異なり、ソート済み配列と二分探索の組み合わせで実装される。

ほかの連想コンテナとの比較としては、

- メモリ使用量と列挙速度において優位
- 挿入速度と削除速度はほかの実装に劣る
- 検索速度は、`std::map`より高速であることが期待できるが (計算量としては同じ対数時間だが、メモリアクセスが高速)、サイズが大きいときは`std::unordered_map`に劣る

また、このクラスは分類としては`std::queue`や`std::stack`と同様のコンテナアダプタに分類され、キーの配列と値の配列の2つを内部で持ち、それを`std::ranges::zip_view`で綴じあわせて扱う実装となっている。

このコンテナクラスは、ランダムアクセスイテレータをサポートする。

### ほかの連想コンテナとの要件の違い

このクラスは要件として、コンテナクラスと、逆順コンテナクラスであることは満たすが、連想コンテナの要件としては以下を満たさない：

- node handleに関する要件
- イテレータ無効化に関する要件
- 単一要素の挿入と削除に線形時間かかる (挿入位置のイテレータを指定したとしても)

また、このコンテナはメモリアロケータを指定できない設計にもなっている。

`value_type`は、`std::map`では`std::pair<const Key, T>`だが、このクラスは`std::pair<Key, T>`である (`const`がつかない)。

以下の不変条件をもち、メンバ関数のいずれかが例外によって終了した場合には不変条件の状態に復元される (ただし、その復元操作によってコンテナが空になる可能性がある)。ムーブコンストラクタとムーブ代入演算子の場合、両方の引数の不変条件が復元される：

- キーの配列と値の配列が、同じ要素数をもつ
- キーの配列が、指定された比較関数オブジェクトを尊重してソートを行う
- 値の配列内のオフセット`off`の値は、キー配列内のオフセット`off`のキーに関連付けられた値である

## テンプレートパラメータ制約

- `KeyContainer`と`MappedContainer`に指定するコンテナ型は、
  - シーケンスコンテナの要件を満たし、
  - ランダムアクセスイテレータをもち、
  - 例外を送出しないメンバ関数`size()`と`max_size()`をもつこと

## 適格要件

- `Key`が`KeyContainer::value_type`と同じ型であること
- `T`が`MappedContainer::value_type`と同じ型であること

## メンバ関数

### 構築・破棄

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ | C++23
`(destructor)` | デストラクタ | C++23
`operator=` | 代入演算子 | C++23

### イテレータ

名前 | 説明 | 対応バージョン
--- | --- | ---
`begin` | 先頭を指すイテレータを取得する | C++23
`cbegin` | 先頭を指す読み取り専用イテレータを取得する | C++23
`end` | 末尾の次を指すイテレータを取得する | C++23
`cend` | 末尾の次を指す読み取り専用イテレータを取得する | C++23
`rbegin` | 末尾を指す逆イテレータを取得する | C++23
`crbegin` | 末尾を指す読み取り専用逆イテレータを取得する | C++23
`rend` | 先頭の前を指す逆イテレータを取得する | C++23
`crend` | 先頭の前を指す読み取り専用逆イテレータを取得する | C++23

### 領域

名前 | 説明 | 対応バージョン
--- | --- | ---
`empty` | コンテナが空であるかどうかを調べる | C++23
`size` | 要素数を取得する | C++23
`max_size` | 格納可能な最大の要素数を取得する | C++23

### コンテナの変更

名前 | 説明 | 対応バージョン
--- | --- | ---
`clear` | 全ての要素を削除する | C++23
`insert` | 要素を挿入する | C++23
`insert_or_assign` | 要素を挿入、あるいは代入する | C++23
`insert_range` | Rangeを挿入する | C++23
`emplace` | 要素を直接構築する | C++23
`emplace_hint` | ヒントを使って要素を直接構築する | C++23
`try_emplace` | キーが存在しない場合のみ要素を直接構築する | C++23
`erase` | 要素を削除する | C++23
`swap` | コンテンツを交換する | C++23
`extract` | キーのコンテナ、値のコンテナを取得する | C++23
`replace` | キーのコンテナ、値のコンテナを置き換える | C++23

### 要素アクセス

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator[]` | 指定したキーを持つ要素を取得する | C++23
`at` | 指定したキーを持つ要素を取得する | C++23
`count` | 指定したキーにマッチする要素の数を取得する | C++23
`find` | 指定したキーで要素を探す | C++23
`contains` | 指定したキーの要素が含まれているかを判定する | C++23
`equal_range` | 指定したキーにマッチする要素範囲を取得する | C++23
`lower_bound` | 与えられた値より小さくない最初の要素へのイテレータを取得する | C++23
`upper_bound` | 特定の値よりも大きい最初の要素へのイテレータを取得する | C++23

### オブザーバー

名前 | 説明 | 対応バージョン
--- | --- | ---
`key_comp` | キー比較用の関数オブジェクトを取得する | C++23
`value_comp` | 要素比較用の関数オブジェクトを取得する | C++23
`keys` | キーのコンテナを取得する | C++23
`values` | 値のコンテナを取得する | C++23

## メンバ型

名前 | 説明 | 対応バージョン
--- | --- | ---
`key_type` | キーの型。テンプレートパラメータ `Key` | C++23
`mapped_type` | 値の型。テンプレートパラメータ `T` | C++23
`value_type` | 要素の型。`std::pair<key_type, mapped_type>` | C++23
`key_compare` | キー値の大小関係を判定する二項述語の型。テンプレートパラメータ `Compare` | C++23
`value_compare` | 要素値のキー部分で大小関係を判定する二項述語の型。入れ子クラス | C++23
`reference` | 要素への参照型。`std::pair<const key_type&, mapped_type&>` | C++23
`const_reference` | 要素への`const`参照型。`std::pair<const key_type&, const mapped_type&>` | C++23
`size_type` | 要素数を表す符号なし整数型 `size_t` | C++23
`difference_type` | 同一のコンテナを指す `iterator` の差を表す符号付き整数型 `ptrdiff_t` | C++23
`iterator` | ランダムアクセスイテレータ | C++23
`const_iterator` | 読み取り専用ランダムアクセスイテレータ | C++23
`reverse_iterator` | 逆順ランダムアクセスイテレータ。`std::reverse_iterator<iterator>` | C++23
`const_reverse_iterator` | 読み取り専用逆順ランダムアクセスイテレータ。`std::reverse_iterator<const_iterator>` | C++23
`key_container_type` | キーを格納するコンテナ型 `KeyContainer` | C++23
`mapped_container_type` | 値を格納するコンテナ型 `MappedContainer` | C++23
`containers` | キーのコンテナと値のコンテナを保持する型 | C++23
`key_equiv` | 要素をとってキーの等価比較を行う説明専用の関数オブジェクト | C++23

## 非メンバ関数

### 要素削除

名前 | 説明 | 対応バージョン
--- | --- | ---
`erase_if` | 指定した条件に合致する要素とその分の領域を、コンテナから削除する | C++23

## 非メンバ（Hidden friends）関数

### 比較演算子

名前 | 説明 | 対応バージョン
--- | --- | ---
`operator==` | 左辺と右辺が等しいかの判定を行う | C++23
`bool operator!=(const flat_map& x, const flat_map& y);` | 左辺と右辺が等しくないかの判定を行う (`==`により使用可能) | C++23
`operator<=>` | 三方比較を行う | C++23
`bool operator<(const flat_map& x, const flat_map& y);` | 左辺が右辺より小さいかの判定を行う (`<=>`により使用可能) | C++23
`bool operator<=(const flat_map& x, const flat_map& y);` | 左辺が右辺より小さいか等しいかの判定を行う (`<=>`により使用可能) | C++23
`bool operator>(const flat_map& x, const flat_map& y);` | 左辺が右辺より大きいかの判定を行う (`<=>`により使用可能) | C++23
`bool operator>=(const flat_map& x, const flat_map& y);` | 左辺が右辺より大きいか等しいかの判定を行う (`<=>`により使用可能) | C++23

### 入れ替え

名前 | 説明 | 対応バージョン
--- | --- | ---
`swap` | 2つの`flat_map`オブジェクトを入れ替える | C++23

## 推論補助

名前 | 説明 | 対応バージョン
--- | --- | ---
`(deduction_guide)` | クラステンプレートの推論補助 | C++23

## その他

名前 | 説明 | 対応バージョン
--- | --- | ---
`uses_allocator` | `flat_map`による特殊化 | C++23

## 例

### 基本的な使い方

    #include <iostream>
    #include <string>
    #include <flat_map>

    int main()
    {
      // stringをキー、intを値として扱う連想配列
      std::flat_map<std::string, int> fm = {
        {"Carol", 4},
        {"Alice", 3},
        {"Bob", 1}
      };

      // 検索 : キー(string)を指定し、値(int)を得る
      int r = fm.at("Alice");
      std::cout << r << std::endl;

      // 全体を出力する
      for (const auto& [key, value] : fm) {
        std::cout << key << " : " << value << std::endl;
      }
    }

#### 出力

    3
    Alice : 3
    Bob : 1
    Carol : 4

### ユーザー定義型をキーとして使用する (`operator<=>`を定義)

    #include <iostream>
    #include <string>
    #include <flat_map>

    // 要素がひとつの場合
    struct MyInt {
      int value;

      friend auto operator<=>(const MyInt& a, const MyInt& b) noexcept {
        return a.value <=> b.value;
      }
    };

    // 要素が複数の場合
    struct Person {
      int id;
      int age;
      std::string name;

      friend auto operator<=>(const Person& a, const Person& b) noexcept {
        if (auto comp = a.id <=> b.id; comp != 0) {
          return comp;
        }
        if (auto comp = a.age <=> b.age; comp != 0) {
          return comp;
        }
        return a.name <=> b.name;
      }
    };

    int main()
    {
      std::flat_map<MyInt, int> fm1 {
        {MyInt{1}, 3},
        {MyInt{2}, 1},
        {MyInt{3}, 4},
      };
      std::cout << fm1[MyInt{2}] << std::endl;

      std::flat_map<Person, int> fm2 {
        {Person{1, 18, "Alice"}, 3},
        {Person{2, 30, "Bob"}, 1},
        {Person{3, 30, "Carol"}, 4},
      };
      std::cout << fm2[Person{2, 30, "Bob"}] << std::endl;
    }

#### 出力

    1
    1

### ユーザー定義型をキーとして使用する (大小比較の関数オブジェクトを定義)

    #include <iostream>
    #include <string>
    #include <tuple>
    #include <flat_map>

    // 要素がひとつの場合
    struct MyInt {
      int value;
    };

    struct MyIntLess {
      bool operator()(const MyInt& a, const MyInt& b) const noexcept {
        return a.value < b.value;
      }
    };

    // 要素が複数の場合
    struct Person {
      int id;
      int age;
      std::string name;
    };

    struct PersonLess {
      bool operator()(const Person& a, const Person& b) const noexcept {
        // キーとして比較したい要素を列挙する
        return std::tie(a.id, a.age, a.name) < std::tie(b.id, b.age, b.name);
      }
    };

    int main()
    {
      std::flat_map<MyInt, int, MyIntLess> fm1 {
        {MyInt{1}, 3},
        {MyInt{2}, 1},
        {MyInt{3}, 4},
      };
      std::cout << fm1[MyInt{2}] << std::endl;

      std::flat_map<Person, int, PersonLess> fm2 {
        {Person{1, 18, "Alice"}, 3},
        {Person{2, 30, "Bob"}, 1},
        {Person{3, 30, "Carol"}, 4},
      };
      std::cout << fm2[Person{2, 30, "Bob"}] << std::endl;
    }

#### 出力

    1
    1

## バージョン

### 言語

- C++23

### 処理系

- Clang: ??
- GCC: ??
- Visual C++: ??

## 参照

- P0429R3 A Standard `flat_map`
  - C++23で`flat_map`が導入された経緯・動機・設計について記載されている
- P0429R9 A Standard `flat_map`
  - C++23で導入された`flat_map`の仕様
- P3567R2 flat_meow Fixes
  - C++26で`swap`の条件付き`noexcept`、`insert_range`のソート済みオーバーロード追加などの修正が行われた