简体   繁体   中英

What is std::views::all introduced for in C++20?

#include <vector>
#include <ranges>

int main()
{
    auto v = std::vector{1, 2, 3, 4};
    v | std::views::drop(2); // ok
    std::views::all(v) | std::views::drop(2); // also ok
}

Successfully compiled with g++11 -std=c++20 . But I cannot tell any difference between v | std::views::drop(2) v | std::views::drop(2) and std::views::all(v) | std::views::drop(2) std::views::all(v) | std::views::drop(2) .

So, my question is:

What is std::views::all introduced for in C++20?

But I cannot tell any difference between v | std::views::drop(2) v | std::views::drop(2) and std::views::all(v) | std::views::drop(2) std::views::all(v) | std::views::drop(2) .

Indeed, there is no difference between the two - because v | views::drop(2) v | views::drop(2) already means views::all(v) | views::drop(2) views::all(v) | views::drop(2) .

views::all is an implementation detail of Ranges to ensure that range adaptors always adapt views (not ranges). All that views::all(v) does is ensure that the result is a View, which is to say (from [range.all] ):

Given a subexpression E , the expression views::all(E) is expression-equivalent to:

  • decay-copy(E) if the decayed type of E models view .
  • Otherwise, ref_view{E} if that expression is well-formed.
  • Otherwise, subrange{E} .

In your case, v is a vector<int> , which does not model view . But it is an lvalue, so ref_view{v} would be well-formed, so that's what happens.

All the adaptors use views::all internally. For instance, drop_view has the following deduction guide:

template <class R>
drop_view(R&&, range_difference_t<R>) -> drop_view<views::all_t<R>>;

So if you wrote drop_view(v, 2) (and you should never use meow_view directly, always use views::meow ), that would itself invoke views::all for you.

You may want your interface to return a range instead of the underlying container. In the example below, container_api exposes member methods (ie of std::vector) that aren't part of a view (eg rbegin(), capacity(), max_size()). range_api exposes operator bool , which isn't part of a vector.

Another important difference is that the return type of range_api is an object and not a reference. This may prevent unintentional copies from users thinking they are getting a range when the actual interface is returning a reference to a container.

class Foo {
public:
     Foo() { ... }
     const auto& container_api() const { return m_vec; }
     auto range_api() const { return std::views::all(m_vec); }
private:
     std::vector<int> m_vec;
};

void some_fn(const Foo& foo)
{
   auto rng = foo.container_api();   // unwanted copy!
   ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM