Search code examples
c++boosttype-erasureboost-type-erasure

What is the meaning of template parameters in boost::any_range?


I've been surfing the internet in search of some well-documented reference for stuff like boost::any_range, but all I've managed to find is an official source which only gives a brief explanation of what any_range is about and presents some basic signatures. I'm looking for something which would explain it in detail.

A basic template for any_range looks like this:

template<
    class Value
  , class Traversal
  , class Reference
  , class Difference
  , class Buffer = any_iterator_default_buffer
>
class any_range;

What is the meaning of each template parameter, and what values can it hold?


Solution

  • any_range is a type-erased container which allows you to store ranges which have at least the capabilities required by the template parameters you supply.

    It is based on any_iterator, for which you can find detailed information in this article.

    Note that the template parameters in the documentation are missing some default arguments which are in the code itself. The real definition has:

    template<
        class Value
      , class Traversal
      , class Reference = Value&
      , class Difference = std::ptrdiff_t
      , class Buffer = use_default
    >
    class any_range
    

    The Value parameter specifies the type of the elements exposed by the range. So an any_range<int,...> may store a std::vector<int>, or a std::list<int>, etc.

    The Traversal parameter specifies the category of range which is allowed, e.g. random access, forward, input. It can be one of the options from iterator_categories. An any_range<int, random_access_tag, ...> would be able to store a std::vector<int>, but not a std::list<int>, because std::list is only bidirectional, not random-access.

    The Reference parameter indicates which type should be returned when you dereference iterators for the range. It defaults to Value&, and that's fine for most cases. (One case where it would not be okay is if your ranges return proxy references, like std::vector<bool> does)

    The Difference indicates which type should be returned when you subtract one iterator for the range from another, getting the difference between them. This defaults to std::ptrdiff_t which is also fine for most cases.

    Finally, the Buffer parameter indicates how to store the underlying type-erased range. This defaults to any_iterator_default_buffer, which stores the underlying range inside the any_range object so long as it's 64 bytes or less. Otherwise it heap allocates it. Other options for this are any_iterator_buffer<MaxStackSize>, any_iterator_heap_only_buffer, and any_iterator_stack_only_buffer<StackSize>.

    (Sources: I got all of this by reading the source code)