AmirSalar
AmirSalar

Reputation: 347

Use ranged algorithm on custom container

I want to upgrade my custom container to compatible with std::ranges algorithms such as find_if and others, like bellow

auto is_satisfy = [](CustomContainer::value_type x) { ... };
std::ranges::find_if(custom_container, is_satisfy);
// instead of std::find_if(custom_container.begin(), custom_container.end(), is_satisfy);

Signature of std::ranges::find_if like as

struct find_if_fn {
   template< ranges::input_range R,
            class Proj = std::identity,
            std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>,
                                         Proj>> Pred >
   constexpr ranges::borrowed_iterator_t<R>
   operator()( R&& r, Pred pred = {}, Proj proj = {} ) const
   {
       return (*this)(ranges::begin(r), ranges::end(r), std::ref(pred), std::ref(proj));
   }
};

What is the input_range concept and how this feature is supported by my own custom container?

Upvotes: 3

Views: 206

Answers (1)

eerorika
eerorika

Reputation: 238351

What is the input_range concept

It is this:

template<class T>
  concept input_­range =
    range<T> && input_­iterator<iterator_t<T>>;

In English, input_range is a range whose iterator is an input_iterator. The range concept on the other hand is:

The range concept defines the requirements of a type that allows iteration over its elements by providing an iterator and sentinel that denote the elements of the range.

template<class T>
  concept range =
    requires(T& t) {
      ranges::begin(t); // sometimes equality-preserving
      ranges::end(t);
    };

And input_iterator is:

The input_­iterator concept defines requirements for a type whose referenced values can be read (from the requirement for indirectly_­readable ([iterator.concept.readable])) and which can be both pre- and post-incremented. [Note 1: Unlike the Cpp17InputIterator requirements ([input.iterators]), the input_­iterator concept does not need equality comparison since iterators are typically compared to sentinels. — end note]

template<class I>
  concept input_­iterator =
    input_­or_­output_­iterator<I> &&
    indirectly_­readable<I> &&
    requires { typename ITER_CONCEPT(I); } &&
    derived_­from<ITER_CONCEPT(I), input_iterator_tag>;

You can go read the specs for the dependee concepts, functions and traits for exact details.

how this feature is supported by my own custom container?

In short: By conforming to the concepts shown above.

In medium: Provide member functions begin and end of which former should return an input iterator and latter should return a compatible sentinel type (which may be same or different from the iterator type). The end sentinel should be reachable from the beginning and represents one past the last element of the range.

In general, I recommend looking at API of standard containers to find out what members they provide and how they work. Copy the design to your custom containers.


Quotes are from the latest standard draft.

Upvotes: 4

Related Questions