最終更新日時(UTC): 2026年05月21日 03時03分23秒
Akira Takahashi が更新

履歴 編集

class template
<ranges>

# std::ranges::cache_latest_view(C++26)

    namespace std::ranges {
      template<input_range V>
        requires view<V>
      class cache_latest_view : public view_interface<cache_latest_view<V>> { …… }; // (1)

      namespace views {
        inline constexpr /*unspecified*/ cache_latest = /*unspecified*/;             // (2)
      }
    }

## 概要

- (1): 元のRangeの最後にアクセスした要素 (間接参照結果) をキャッシュする`view`
- (2): `cache_latest_view`を生成するRangeアダプタオブジェクト

`views::transform`と`views::filter`を組み合わせた場合、`filter`が条件判定のために要素を間接参照し、さらに`for`文の本体で同じ要素を参照することにより、変換関数が2回呼び出される。`cache_latest`を間に挟むことで、間接参照の結果をキャッシュし、変換関数の重複呼び出しを回避できる。

    v | std::views::transform(expensive) // 重い変換関数
      | std::views::cache_latest         // 変換結果をキャッシュ
      | std::views::filter(pred)

キャッシュ戦略は、元のRangeの参照型が参照型である場合はポインタを、非参照型 (prvalue) である場合は値そのものを保持する。

### Rangeコンセプト

borrowed | sized | output | input | forward | bidirectional | random_access | contiguous | common | viewable | view
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
| ※ |  | ○ |  |  |  |  |  | ○ | ○

- ※: `V`が`sized_range`のとき
- イテレータと番兵の型が異なるため`common_range`ではない
- 内部状態としてキャッシュを持つため`forward_range`以上にはならない
- キャッシュへのポインタを保持するため`borrowed_range`ではない

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

- `input_range<V>`
- `view<V>`

## 効果

- (2): 式`views::cache_latest(E)`の効果は`cache_latest_view(E)`と等しい

## メンバ関数

名前 | 説明 | 対応バージョン
--- | --- | ---
`(constructor)` | コンストラクタ | C++26
`base` | `V`の参照を取得する | C++26
`begin` | 先頭を指すイテレータを取得する | C++26
`end` | 番兵を取得する | C++26
`size` | 要素数を取得する | C++26

## 継承しているメンバ関数

名前 | 説明 | 対応バージョン
--- | --- | ---
`empty` | Rangeが空かどうかを判定する | C++26
`operator bool` | Rangeが空でないかどうかを判定する | C++26
`front` | 先頭要素への参照を取得する | C++26

## メンバ型

名前 | 説明 | 対応バージョン
--- | --- | ---
`iterator` | イテレータ型(説明専用) | C++26
`sentinel` | 番兵型(説明専用) | C++26

## 推論補助

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

## 例

### 基本的な使い方

    #include <ranges>
    #include <print>
    #include <vector>

    int main()
    {
      std::vector v = {1, 2, 3, 4, 5};

      for (auto x : v | std::views::cache_latest) {
        std::println("{}", x);
      }
    }

#### 出力

    1
    2
    3
    4
    5

### 変換関数の重複呼び出しを抑える

`views::transform`で重い変換を行い、`views::filter`で絞り込む場合、`filter`が条件判定で要素を間接参照し、その後の処理で再度間接参照されるため、変換関数が要素ごとに複数回呼び出される。間に`cache_latest`を挟むことで、変換関数の呼び出しを各要素1回に抑えられる。

    #include <ranges>
    #include <print>
    #include <vector>

    int main()
    {
      std::vector v = {1, 2, 3, 4, 5};

      int call_count = 0;
      auto square = [&](int x) { ++call_count; return x * x; };

      for (auto x : v | std::views::transform(square)
                      | std::views::cache_latest
                      | std::views::filter([](int n) { return n > 5; })) {
        std::println("{}", x);
      }
      std::println("call_count: {}", call_count);
    }

#### 出力

    9
    16
    25
    call_count: 5

## バージョン

### 言語

- C++26

### 処理系

- Clang: 21 ✅
- GCC: 15.1 ✅
- Visual C++: 2026 Update 2 ❌

## 関連項目

- `std::views::transform`
- `std::views::filter`

## 参照

- P3138R5 `views::cache_latest`