[英]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
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.