簡體   English   中英

為什么每個循環的 c++ 接受右值但 std::ranges 不接受?

[英]Why does c++ for each loops accept r-values but std::ranges do not?

像這樣的語句編譯沒有錯誤:

for (int i : std::vector<int>({0, 1}))
  std::cout << i;

但是這樣的聲明不會:

std::vector<int>({0, 1}) |
  std::views::filter([](int i) { return true; });

為什么每個循環都允許 r 值,但 std::range 管道中不允許? 有沒有辦法讓我可以像第二個一樣工作,而不必聲明變量?

for 循環工作正常,因為vector<int> (右值)在評估循環時有效。

第二個代碼片段有兩個問題:

  • 謂詞必須返回一個bool
  • 您在視圖 object 中使用的vector<int>在評估時懸空,因此編譯器不接受它。

如果不是vector<int>右值,object 不能懸掛(左值)或將引用保存到不能懸掛的其他東西中,這將起作用。

例如:

auto vec = std::vector<int>({0, 1});
auto vw = vec | std::ranges::views::filter([](int i) { std::cout << i; return true; });

或者你可以傳遞一個右值,它引用了一個非懸掛vector<int> object,比如std::span

auto vec = std::vector<int>({0, 1});
auto vw = span{vec} | std::ranges::views::filter([](int i) { std::cout << i; return true; })

這里, std::span仍然是一個右值,但是編譯器接受它,因為std::span的作者已經為它創建了一個異常。

對於引用其他內容(通常是視圖)的自定義類型,您可以通過創建模板變量enable_borrowed_range的特化來創建自己的異常。

在矢量的情況下,它看起來像這樣(但不要這樣做! ):

template<> // don't do this
inline constexpr bool ranges::enable_borrowed_range<std::vector<int>> = true;

您的代碼現在可以編譯,但它會觸發未定義的行為,因為一旦評估視圖,向量就會懸空。

這適用於最新的 MSVC STL 和 libstdc++(演示),感謝P2415R2

在 P2415R2 之前, filter_view始終通過引用(通過ref_view )存儲基礎vector 存儲vector的副本被認為是不明智的。 因為視圖應該是廉價復制、廉價移動和廉價銷毀。 存儲vector的副本會帶來意想不到的性能損失。

由於生命周期問題,引用右值vector沒有意義。

但 P2415R2 指出,視圖也可以是不可復制的,同時移動和銷毀的成本仍然很低。

因此 P2415R2 引入了owning_view ,一個存儲范圍右值副本的不可復制視圖,並使標准范圍適配器使用該視圖。

最終結果是,從vector右值創建filter_view與實現 P2415R2 的標准庫實現一起工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM