对于函数来说,接受对范围而不是视图的转发引用有好处吗?

Mar*_*rkB 2 c++ c++-concepts c++20 std-ranges

std::ranges::range在 C++20 之前,当需要将a 作为参数时,有必要在模板函数中使用转发引用。由于 C++20 中提供了概念,因此现在可以将按std::ranges::view值传递给泛型函数。根据标准,视图是一个范围。

考虑以下代码。

#include <vector>
#include <ranges>
#include <iterator>
#include <iostream>

template <std::ranges::range Range>
void fn1(Range range)   // intentionally not a forwarding reference
{
    for (auto& elem : range) {
        ++elem;
    }
}

template <std::ranges::view View>
void fn2(View view)
{
    for (auto& elem : view) {
        ++elem;
    }
}

int main()
{
    std::vector<int> v{1,2,3};
    fn1(v); // doesn't increment, since a copy of 'v' is used in 'fn1'.
    /* fn2(v); // fails to compile, since 'v' cannot be implicitly converted to a view */
    fn1(std::views::all(v)); // increments, since a ref_view is passed to fn1
    fn2(std::views::all(v)); // increments, as expected
    for (int val : v)
        std::cout << val << ' '; // 3 4 5
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我没有什么特别反对转发参考文献的内容。人们可以声称能够直接将一个对范围建模的对象传递到通用函数中(例如fn1(v)),从而提高可读性。

这纯粹是一个偏好问题,还是在决定将通用函数参数实现为Range&&or时还有其他考虑因素View

Nic*_*las 6

从广义上讲,这是一个坏主意。

大多数范围不是视图。这个ranges::view概念要求类型选择成为视图。容器不是视图;而是视图。它们是容器。span是一个视图,但vector不是。此外,大多数容器不能是视图,因为视图要求复制/移动是恒定时间的操作。而对于大多数容器来说,这是不可能的。

因此,通过特定地限制模板view,您基本上可以强制用户将他们传递给函数的任何内容包装在某种视图类型中。这会在调用方产生大量没有任何用处的语法噪音。

  • @MarkB 因为 `const Range&amp;` 不一定是有效范围,所以请考虑没有 `const` 限定的 `begin()` 的范围。 (3认同)