Linking the lifetime of a container to a range

It is often useful, especially when returning ranges, to make a container and then to return a view of it. Often the container can be destructed once the last copy of the view goes out of scope.

auto constexpr view_shared

Return a view on a heavyweight range whose lifetime is tied to the view.

Normally, the onus is on the user to make sure that the container, say, that a view is on, remains in scope while the view is being used. However, sometimes this is impossible or undesirable. For example, returning a range of which the type is an implementation detail is fraught with difficulty.

The solution is to force the range to stay in memory as long as the view or any copy or derived view does. That is what this function does, by keeping the range in a std::shared_ptr.

The optional second argument is a function to convert the range into a view. This is a function, not the view itself, because the range usually first needs to be copied into the shared_ptr, before a view of the copy can be produced.

  • heavyweight -

    The heavyweight range that the view will be on. If this is a std::shared_ptr, a copy of it will be kept. If this is a range, then a copy of it will be kept in a shared_ptr.

  • make_view -

    (optional) Function that returns the right sort of view of the range. If this is not given, view is used. Other simple or complex functors are possible. For example, use reverse to produce a reversed view of the range.

Type erasure

Sometimes it is irrelevant what the type of a range is, for example at API boundaries. range::any_range knows what the type of the elements is, and what the range can do, but hides what the actual type of the range is.

auto constexpr make_any_range

Create an any_range object from a range, with best-guess type parameters.

If directions are given, they specify the directions that the range should be traversed in. Otherwise, the default direction will be used, and its reverse, if applicable.

The any_range always has the correct type for default_direction.

The element type is set to the result type of first (range), in the first direction given (or the default direction). make_any_range can only be used if this is implemented.

  • range -

    The actual range the any_range will give a view on.

  • directions -

    (optional; any number of arguments is allowed) The directions that should be passed to range::view to view the range. If left out, the default direction is used to call view, and the any_range will allow traversal in that direction and its reverse, if applicable.

template <class Element, class Capabilities = void>
class range::any_range

A homogeneous range that hides the type of the underlying range.

It wraps any range that has elements of a specific type, and the capabilities given. any_range is homogeneous. The underlying range’s elements must be convertible to the any_range‘s type. (If they are not, using range::transform with a function that performs the conversion can help.)

Most operations require a virtual method call, so performance is decreased compared to using the underlying range directly. Additionally, some operations require a heap allocation. chop_in_place can be quite efficient if it is implemented on the underlying range. drop(), and chop() with an lvalue, however, need to allocate the new underlying range, and can be slow.

Implicit conversion between different any_range types is possible as long as they have the same Element type and the list of target capabilities is a subset of the source capabilities. This conversion can involve a number of memory allocations. If the Element types are different, then conversion is also possible but explicit, since it works as with any other range type. It causes an additional layer of virtual calls and allocations, so this is something to be careful with.

Each of the other map_element should have a direction as a key, and a meta::set of available capabilities for that as the value. These classes are defined in namespace range::capabilities:

  • range::capability::empty,
  • range::capability::size,
  • range::capability::first,
  • range::capability::drop_one,
  • range::capability::drop_n,
  • range::capability::chop_destructive.
There are also predefined meta::map types for some types of ranges, all with direction::front as the default direction:
  • range::capability::unique_capabilities,
  • range::capability::forward_capabilities,
  • range::capability::bidirectional_capabilities,
  • range::capability::random_access_capabilities.
If this parameter is not given, range::capability::forward_capabilities is used.
  • Element -

    The type that first(r) returns.

  • Capabilities -

    (optional) A meta::map with meta::map_element types indicating the capabilities of the underlying range. One of these must have key range::capability::default_direction, with the default direction as the value. Another will often have key range::capability::copy_construct, with a void value, to indicate that the underlying range (and therefore the any_range) supports copy construction.

Table Of Contents

Previous topic


Next topic


This Page