← SEARCHABLE ARCHIVE
C / C++ · 2026-08-12

C++ 從基礎到精通 — 第 18 講

使用 Ranges 與 Views 建立延遲資料管線

INTERACTIVE READING MODE →

本部落格文章以教學為目的撰寫。 內容可能有誤,請搭配目標編譯器與標準函式庫文件確認。

Iterator 將容器與演算法分離,但傳統呼叫需要反覆傳入 begin 與 end。C++20 Ranges 能直接接收範圍,Views 則能組合不複製資料的延遲轉換。

直接傳入範圍

std::vector<int> scores{30, 80, 50, 100};
std::ranges::sort(scores);

auto found = std::ranges::find(scores, 80);
if (found != scores.end())
{
    // 找到值。
}

不必分別寫 begin 與 end,可降低混用不同容器 iterator 的風險。projection 也能直接指定成員。

std::ranges::sort(players, {}, &Player::Score);

View 在需要時才計算

auto visibleNames = players
    | std::views::filter([](const Player& p) { return p.IsVisible; })
    | std::views::transform([](const Player& p) -> const std::string&
      {
          return p.Name;
      })
    | std::views::take(10);

for (const std::string& name : visibleNames)
    DrawName(name);

此管線不會建立三個中間 vector。迭代要求元素時才執行 filter 與 transform,take(10) 最多處理十筆。

多數 View 不擁有來源資料

auto MakeBadView()
{
    std::vector<int> local{1, 2, 3};
    return local | std::views::filter([](int value) { return value > 1; });
}

回傳的 View 參考區域 vector,但函式結束後 vector 已被銷毀。之後迭代會存取失效物件。

儲存或回傳 View 前,必須證明來源 range 的生命週期涵蓋所有使用。如果結果需要獨立擁有資料,就明確收集到容器中。

延遲求值也會把錯誤與副作用推遲到迭代時。修改來源容器仍可能讓 iterator 失效。

Ranges 的價值是用組合描述資料流程,而不只是縮短語法。管線過長或混入狀態修改時,應命名中間階段或改用明確的演算法與迴圈。