- ranges[meta header]
- std::ranges[meta namespace]
- class template[meta id-type]
- cpp26[meta cpp]
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) である場合は値そのものを保持する。
| borrowed |
sized |
output |
input |
forward |
bidirectional |
random_access |
contiguous |
common |
viewable |
view |
|
※ |
|
○ |
|
|
|
|
|
○ |
○ |
- (2): 式
views::cache_latest(E)の効果はcache_latest_view(E)と等しい
#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);
}
}
- views::cache_latest[color ff0000]
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);
}
- views::cache_latest[color ff0000]
- std::views::transform[link transform_view.md]
- std::views::filter[link filter_view.md]
- Clang: 21 [mark verified]
- GCC: 15.1 [mark verified]
- Visual C++: 2026 Update 2 [mark noimpl]