views::filter 与 if-continue 相比有什么优势?

问题描述 投票:0回答:3

我已经使用范围有一段时间了,每次使用过滤时,我都觉得它可以轻松地用普通的旧

if
continue
语句替换。考虑这些代码片段:

for (auto value : values | ranges::views::filtered([](auto value) { /* ... */ })) {
    // ... do something with value
}

for (auto value : values) {
    if (/* ... */) continue;
        // ... do something with value
}

对我来说,第二个选项看起来更具可读性。此外,第一个选项可能会涉及一些额外的调用开销。那么过滤有哪些优点呢?是否有一些关于我何时应该选择其中之一的指南?

c++ loops std-ranges
3个回答
2
投票

第一个版本是 C++ 笨拙的 lambda 语法的受害者。如果您已经有一个现成的谓词或使用 lambda 库来表示短 lambda,再加上命名空间别名,那么看起来会更好看。

namespace srv = std::ranges::views;
for (auto const& value : values | srv::filter(&Widget::is_visible)) {
  // ...
}

现在,它的优点是其意图非常明确,而不仅仅是像早期的 continue 那样只是一种模式。您可能会从优化构建中的两个版本中获得非常相似的程序集。


1
投票

这感觉像是一个基于意见的问题,但是让我给你和我在 JavaScript 或任何其他带有集合/序列操作库的语言中问这个问题时给出的相同的观点:

(几乎)您对奇特视图和范围所做的所有操作都可以通过调用

reduce
来完成(它在 C++ 中有很多名称,来自 C++23 的
std::ranges::fold_left
,来自 C++17 的
std::reduce
)和
std::accumulate
)。

reduce

能做的一切都可以用 for 循环来完成。

当您执行单个操作时,几乎总是有一个算法。如果没有,你可以自己写一个。

当循环中有多个操作时,事情会变得更加复杂。在这种情况下,范围通常会变得更具可读性、更具声明性,并且其意图更清晰(即自记录代码)。

我会尝试举一个例子来强调这一点:

auto input = get_vector<int>(); std::vector<widget_type> output{}; output.reserve(input.size()); for (auto item : input) { if (item % 2 == 0) continue; auto widget = get_widget_by_index(item + 1); if (widget.hidden()) continue; output.emplace_back(std::move(widget)); } output.shrink_to_fit();

很容易阅读,但与此相比:

auto output = views::all(get_vector<int>()) // views::all is to allow the immediate use of temporaries without lifetime issues | views::filter([](auto i) { return i % 2 != 0; }) | views::transform([](auto i) { return i + 1 }) | views::transform(&get_widget_by_index) | views::filter(&widget_type::hidden) | ranges::to<std::vector>();



-2
投票
continue

)更容易阅读,与旧的 C++ 标准兼容,并且非常接近后面的实际执行。第一个版本很可能会优化为非常接近的二进制代码,但在我看来,它的语法过于复杂,并且涉及后面模板类的大量编译时优化。

第一个版本的优势为零。你的想法很好,随着最近的 C++ 功能,人们往往会过度思考并导致迭代膨胀。

编辑

:评论指出我对临时过滤列表分配的看法是错误的。因此,这两个代码最终可能会产生完全相同的指令。然而,第二个版本更简单、更易读并且与旧的 C++ 标准兼容且没有缺点的论点仍然成立。 您还有一个略有不同的版本:

for (auto value : values) { if (!...) { //Do stuff here } }

我倾向于更喜欢那个,因为控制流在视觉上比
continue

更明显。但这完全是个人品味问题。

    

© www.soinside.com 2019 - 2024. All rights reserved.