| Home | Libraries | People | FAQ | More

## Reference

### Polymorphism models

The key aspect of dynamic polymorphism is the ability for a value of type `T` to internally use another value of a possibily different type `U` for the implementation of a given interface. Base/derived polymorphism is the classic model of dynamic polymorphism in C++, but not the only possible one.

Formally, a polymorphism model is defined by

- A family Interface of permissible interface types and, for each `I` ∈ Interface, the family Implementation(`I`) of types satisfying `I`.
- For a given interface type `I`, an operation subobject(`x`) that maps each value of an implementation type to its internally used value `y` of a possibly different implementation type [21].

Static polymorphism is the trivial case where subobject(`x`) = `x` for all `x`. Base/derived polymorphism is characterized by:

- Interface = { `Base` : `std::is_polymorphic_v<Base>` }.
- Implementation(`Base`) = { `Derived` : `std::is_base_of_v<Base,Derived>` }.
- subobject(`x`) = `static_cast<Derived&>(x)` with `typeid(x)==typeid(Derived)`.

A polymorphism model is called closed if, for any `I` ∈ Interface, suboject ranges over a finite subset ot types of Implementation(`I`), that is, there is only a finite number of types subojects can belong in. A non-closed model is called open.

### Polymorphic containers

A polymorphic container is an object that stores objects of some type `T` implementing a given interface `I` under an implicitly associated polymorphism model. Polymorphic containers satisfy the requirements for `Container` and `AllocatorAwareContainer` with the following modifications:

- Where it occurs, replace the requirement that `T` be `CopyInsertable`, `CopyAssignable`, `MoveInsertable`, `MoveAssignable` or `EqualityComparable`, with the following semantic clause: may throw if some subobject in the container is not `CopyConstructible` (respectively, `CopyAssignable`, `MoveConstructible`, `MoveAssignable`, `EqualityComparable`).
- Replace [container.requirements.general]/3 with: `allocator_type` must have the property that for any type `U` implementing `I` and the associated type `A` = `std::allocator_traits<allocator_type>::rebind_alloc<U>`, `U` is `CopyInsertable` (respectively `MoveInsertable`) with respect to `A` if and only if `U` is `CopyConstructible` (respectively `MoveConstructible`); all subobjects of type `U` stored in these containers shall be constructed using the `std::allocator_traits<A>::construct` function and destroyed using the `std::allocator_traits<A>::destroy` function; these functions (or their equivalents for a rebound allocator) are called only for the types of the stored subobjects, not for any other type (internal or public) used by the container.

#### Polymorphic collections

Polymorphic collections store their objects of type `value_type` in segments dedicated to each of the types of the contained subojects. Only objects whose subobjects are of an acceptable type are allowed, where a type `U` is said to be acceptable if

- it implements the interface associated to the container,
- it is `MoveConstructible`,
- it is `MoveAssignable` or `std::is_nothrow_move_constructible<U>::value` is `true`.

The collection is open (resp. closed) if its associated polymorphism model is open (resp. closed). Polymorphic collections conform to the requirements of `PolymorphicContainer` with the following modifications and extra guarantees:

- The complexity of `empty()` and `size()` is linear on the number of segments of the collection.
- `max_size()` is not provided.
- `a==b` evaluates to `true` iff for each non-empty segment of subojects of type `U` in `a` there is a segment of `U` in `b` with the same size and equal elements in the same order, and vice versa.
- No exceptions are thrown associated to some subobject type not being `CopyAssignable`, `MoveConstructible` or `MoveAssignable`.

A type `U` is said to be registered into the collection if a (possibly empty) segment for `U` has been created. Registered types continue to stay so for the duration of the container except if it is moved from, assigned to, or swapped. For closed collections, all acceptable types are automatically registered upon construction.

Each segment has an associated capacity indicating the maximum size that it can attain without reallocation. When the limit is exceeded (or explicitly through `reserve`) new storage space is allocated with greater capacity and elements are moved.

Collection traversal goes through the elements of the first segment, then the second, etc. For open collections, the order in which segments are visited is unspecified but remains stable until a new segment is created. For closed collections, segment order is fixed and determined by the specification of the collection type.

Besides `iterator` and `const_iterator`, there are iterator types `local_base_iterator` and `local_iterator<U>` (and their `const_` counterparts) whose objects can be used to iterate over the segment for `U` (in the same order followed by global traversal). Local base iterators refer to `value_type`, whereas (`const_`)`local_iterator<U>` refers to `U`. All local iterators model `RandomAccessIterator`. Local base iterators may not be used to iterate across segments, and comparing local base iterators associated to different segments is undefined behavior. A (const) local base iterator to a segment for `U` can be explicitly converted to (`const_`)`local_iterator<U>` pointing to the same position, and vice versa.

Insertion and erasure do not invalidate iterators (global or local) except those from the insertion/erasure point to the end of the affected segment, if its capacity is not exceeded, or all iterators/references to the segment otherwise [22].

For the description of the remaining requirements of polymorphic collections, we use the following notation:

- `C` is a polymorphic collection type,
- `c` is an object of type `C`, `cc` is a possibly `const` object of type `C`,
- `al` is a value of type `C::allocator_type`,
- `info` is a value of type `const C::index_type&`,
- `U` is an acceptable type, `Us...` is a template parameter pack of acceptable types,
- `n` is a value of `size_type`,
- `x` is a value of a type `T` implementing the interface associated to the collection,
- `args...` is a function parameter pack of types `Args&&...`,
- `it` is a possibly const global iterator of `c`,
- `it1` and `it2` are (same-typed) possibly const global iterators of a `C` collection other than `c` such that [`it1`, `it2`) is a valid range.
- `lbit` is a possibly const local base iterator of `c`,
- `lbit1` and `lbit2` are (same-typed) possibly const local base iterators of a `C` collection other than `c` such that [`lbit1`, `lbit2`) is a valid range.
- `lit` is a (`const_`)`local_iterator<U>` of `c`,
- `lit1` and `lit2` are (same-typed) (`const_`)`local_iterator<U>`s of a `C` collection other than `c` such that [`lit1`, `lit2`) is a valid range,
- `i1` and `i2` are iterators external to `c` referring to `T` such that [`i1`, `i2`) is a valid range,
- `j1` and `j2` are iterators external to `c` such that [`j1`, `j2`) is a valid range,
- `xit1` and `xit2` are (same-typed) possibly const iterators (global or local) of `c` such that [`xit1`, `xit2`) is a valid range.

##### Types

`C::type_index`

Can be either `std::type_info` or `std::size_t`. We define `index<U>` as follows:

- if `type_index` is `std::type_info`: `typeid(U)`,
- if `type_index` is `std::size_t`: the index number `i` such that `U` is the `i`-th element in `Us...`, where `Us...` is the list of acceptable types as specified in the associated polymorphism model.

`C::local_base_iterator`

`RandomAccessIterator` with same value type, difference type and pointer and reference types as `C::iterator`, valid for accessing elements of a given segment. Implicily convertible to `C::const_local_base_iterator`, explicitly convertible to `C::local_iterator<U>` if the segment it points to is actually that for `U`.

`C::const_local_base_iterator`

`RandomAccessIterator` with same value type, difference type and pointer and reference types as `C::const_iterator`, valid for accessing elements of a given segment. Explicitly convertible to `C::const_local_iterator<U>` if the segment it points to is actually that for `U`.

`C::local_iterator<U>`

`RandomAccessIterator` with value type `U`, reference type `U&`, pointer type `U*` and the same difference type as `C::iterator`, valid for accessing elements of the segment for `U`. Implicily convertible to `C::const_local_iterator<U>`, explicitly convertible to `C::local_base_iterator`.

`C::const_local_iterator<U>`

`RandomAccessIterator` with value type `U`, reference type `const U&`, pointer type `const U*` and the same difference type as `C::iterator`, valid for accessing elements of the segment for `U`. Explicitly convertible to `C::const_local_base_iterator`.

`C::const_base_segment_info`

`CopyConstructible` and `CopyAssignable` type with information about a given segment of a collection. If `ci` is a possibly `const` object of type `C::const_base_segment_info` associated to the segment of `c` for `U`, then

- `ci.begin()==c.cbegin(index<U>)`
- `ci.cbegin()==c.cbegin(index<U>)`
- `ci.begin<U>()==c.cbegin<U>()`
- `ci.cbegin<U>()==c.cbegin<U>()`
- `ci.end()==c.cend(index<U>)`
- `ci.cend()==c.cend(index<U>)`
- `ci.end<U>()==c.cend<U>()`
- `ci.cend<U>()==c.cend<U>()`
- `ci.type_info()==index<U>`

`C::base_segment_info`

`CopyConstructible` and `CopyAssignable` type publicly derived from `C::const_base_segment_info` and exposing its public interface. Additionally, if `i` is an object of type `C::base_segment_info` associated to the segment of `c` for `U`, then

- `i.begin()==c.begin(index<U>)`
- `i.begin<U>()==c.begin<U>()`
- `i.end()==c.end(index<U>)`
- `i.end<U>()==c.end<U>()`

`C::const_segment_info<U>`

`CopyConstructible` and `CopyAssignable` type with information about the segment for `U`. If `ci` is a possibly `const` object of type `C::const_segment_info<U>` associated to the collection `c`, then

- `ci.begin()==c.cbegin<U>()`
- `ci.cbegin()==c.cbegin<U>()`
- `ci.end()==c.cend<U>()`
- `ci.cend()==c.cend<U>()`

`C::segment_info<U>`

`CopyConstructible` and `CopyAssignable` type publicly derived from `C::const_segment_info<U>` and exposing its public interface. Additionally, if `i` is an object of type `C::segment_info<U>` associated to the collection `c`, then

- `i.begin()==c.begin<U>()`
- `i.end()==c.end<U>()`

`C::base_segment_info_iterator`

`InputIterator` with value type and reference type `C::base_segment_info`.

`C::const_base_segment_info_iterator`

`InputIterator` with value type and reference type `C::const_base_segment_info`.

`C::const_segment_traversal_info`

`CopyConstructible` and `CopyAssignable` type with `const` member functions `begin`/`cbegin` and `end`/`cend` returning `C::const_base_segment_info_iterator` objects that span over a range of `C::const_base_segment_info` objects.

`C::segment_traversal_info`

`CopyConstructible` and `CopyAssignable` type publicly derived from with `C::const_segment_traversal_info` and exposing its public interface. Additionally, provides non-const member functions `begin` and `end` returning `C::base_segment_info_iterator` objects that span over an equivalent range of `C::base_segment_info` objects.

##### Construct/copy/destroy

`C(j1,j2)`
`C d(j1,j2)`

Requires: `C::allocator_type` is `DefaultConstructible`. [`j1`, `j2`) can be inserted into `C`.
Effects: Copy constructs the internal allocator from `C::allocator_type()`. Internally calls `this->insert(j1,j2)` on construction.

`C(j1,j2,al)`
`C d(j1,j2,al)`

Requires: [`j1`, `j2`) can be inserted into `C`.
Effects: Copy constructs the internal allocator from `al`. Internally calls `this->insert(j1,j2)` on construction.

##### Type registration (open collections only)

`c.register_types<Us...>()`

Effects: Registers (if needed) each of the indicated types in the collection.

`cc.is_registered(info)`
`cc.is_registered<U>()`

Returns: `true` iff the indicated type is registered in the collection.

##### Iterators

(1) `c.begin(info)`
(2) `c.begin<U>()`
(3) `const_cast<const C&>(c).begin(info)`
(4) `cc.cbegin(info)`
(5) `const_cast<const C&>(c).begin<U>()`
(6) `cc.cbegin<U>()`

Returns: A `local_base_iterator` (1) or `local_iterator<U>` (2) or `const_local_base_iterator` (3,4) or `const_local_iterator<U>` (5,6) to the beginning of the segment for the indicated type.
Throws: If the indicated type is not registered.

(1) `c.end(info)`
(2) `c.end<U>()`
(3) `const_cast<const C&>(c).end(info)`
(4) `cc.cend(info)`
(5) `const_cast<const C&>(c).end<U>()`
(6) `cc.cend<U>()`

Returns: A `local_base_iterator` (1) or `local_iterator<U>` (2) or `const_local_base_iterator` (3,4) or `const_local_iterator<U>` (5,6) to the end of the segment for the indicated type.
Throws: If the indicated type is not registered.

(1) `c.segment(info)`
(2) `c.segment<U>()`
(3) `const_cast<const C&>(c).segment(info)`
(4) `const_cast<const C&>(c).segment<U>()`

Returns: A `base_segment_info` (1) or `segment_info<U>` (2) or `const_base_segment_info` (3) or `const_segment_info<U>` (4) object referring to the segment for the indicated type.
Throws: If the indicated type is not registered.

(1) `c.segment_traversal()`
(2) `const_cast<const C&>(c).segment_traversal()`

Returns: A `segment_traversal_info` (1) or `const_segment_traversal_info` (2) object spanning over a range of segment descriptors for the collection. The order in which segments are visited matches that of [`c.begin()`, `c.end()`).

##### Capacity

`cc.empty(info)`
`cc.empty<U>()`

Returns: `true` iff the segment for the indicated type exists and is empty.
Throws: If the indicated type is not registered.

`cc.size(info)`
`cc.size<U>()`

Returns: The size of the segment for the indicated type.
Throws: If the indicated type is not registered.

`cc.max_size(info)`
`cc.max_size<U>()`

Returns: The maximum size attainable by the segment for the indicated type.
Throws: If the indicated type is not registered.

`cc.capacity(info)`
`cc.capacity<U>()`

Returns: The maximum size that the segment for the indicated type can attain without requiring reallocation.
Throws: If the indicated type is not registered.

`c.reserve(n)`

Effects: Calls `reserve` with `n` for each of the segments of the collection.

(1) `c.reserve(info,n)`
(2) `c.reserve<U>(n)`

Effects: Throws if the type indicated by `info` is not registered (1) or registers `U` if needed (2). If `n` is greater than the current capacity of the segment for the indicated type, new storage space is allocated with a capacity of at least `n` and elements are moved there.
Complexity: Linear in the size of the segment if reallocation happens, constant otherwise.
Throws: `std::length_error` if `n` is greater than the return value of `max_size` for the segment.

`c.shrink_to_fit()`

Effects: Calls `shrink_to_fit` for each of the segments of the collection.

`c.shrink_to_fit(info)`
`c.shrink_to_fit<U>()`

Effects: Non-binding request to reduce memory usage while preserving the sequence of elements of the segment for the indicated type. May invalidate all iterators and references to the segment.
Throws: If the indicated type is not registered.

##### Modifiers

(1) `c.emplace<U>(args...)`
(2) `c.emplace_hint<U>(it,args...)`

Requires: `U` is constructible from `std::forward<Args>(args)...`.
Effects: Registers `U` (if needed) and inserts a new element with a subobject constructed from `std::forward<Args>(args)...`: (1) at the end of the segment for `U`; (2) just before the position indicated by `it`, if it points to the segment for `U`, or at the end of the segment for `U` otherwise.
Returns: An `iterator` to the newly inserted element.
Complexity: Amortized constant time plus linear in the distance from the insertion position to the end of the segment.

(1) `c.emplace_pos<U>(lbit,args...)`
(2) `c.emplace_pos(lit,args...)`

Requires: `U` is constructible from `std::forward<Args>(args)...`. (1) `lbit` points to the segment for `U`.
Effects: Inserts a new element with a subobject constructed from `std::forward<Args>(args)...` just before the position indicated.
Returns: A `local_base_iterator` (1) or `local_iterator<U>` (2) to the newly inserted element.
Complexity: Amortized constant time plus linear in the distance from the insertion position to the end of the segment.

(1) `c.insert(x)`
(2) `c.insert(it,x)`

Effects: Let `Q` be the type of the subobject of `x`. If `Q` = `T` and `T` is acceptable, registers `T` if needed. If `Q` = `T` and `T` is not acceptable, throws. If `Q` ≠ `T` and `Q` is not registered, throws. If `x` is not a non-const rvalue expression and `Q` is not `CopyConstructible`, throws. Inserts an element with a subobject move constructed or copy constructed from the subobject of `x`: (1) at the end of the corresponding segment; (2) just before the position indicated by `it`, if it points to the corresponding segment, or at the end of the segment otherwise.
Returns: An `iterator` to the newly inserted element.
Complexity: Amortized constant time plus linear in the distance from the insertion position to the end of the segment.

(1) `c.insert(lbit,x)`
(2) `c.insert(lit,x)`

Requires: The type of the subobject of `x` corresponds to the indicated segment.
Effects: Inserts an element with a subobject move constructed or copy constructed from the subobject of `x` just before the position indicated.
Returns: A `local_base_iterator` (1) or `local_iterator<U>` (2) to the newly inserted element.
Complexity: Amortized constant time plus linear in the distance from the insertion position to the end of the segment.

`c.insert(i1,i2)`

Effects: Equivalent to `while(i1!=i2)c.insert(*i1++)`.

`c.insert(it1,it2)`
`c.insert(lbit1,lbit2)`
`c.insert(lit1,lit2)`

Effects: For each of the elements of the range in succession, registers the type of its subobject if needed and inserts it into the collection [23].

`c.insert(it,i1,i2)`

Effects: If `it==c.end()`, equivalent to `while(i1!=i2)c.insert(it,*i1++)`, otherwise inserts each of the elements in [`i1`, `i2`) in succession with a hint pointing to `*it` [24].

`c.insert(it,it1,it2)`
`c.insert(it,lbit1,lbit2)`
`c.insert(it,lit1,lit2)`

Effects: If `it==c.end()`, equivalent to the corresponding hint-less version, otherwise for each of the elements in [`i1`, `i2`) in succession registers the type of its subobject if needed and inserts it into the collection with a hint pointing to `*it` [25].

`c.insert(lbit,i1,i2)`

Requires: The subojects of elements in [`i1`, `i2`) are all of the type corresponding to the indicated segment.
Effects: Inserts a range of elements with subobjects copy constructed from those in [`i1`, `i2`) just before `lbit`.
Returns: A `local_base_iterator` to the beginning of the inserted range.

`c.insert(lit,j1,j2)`

Requires: For each value `x` in [`j1`, `j2`) either (a) `x` is of a type implementing the interface associated to the collection and the subobject of `x` is of type `U` or (b) `U` is constructible from `x`.
Effects: Inserts a range of elements with subobjects copy constructed (a) or constructed (b) from the values in [`j1`, `j2`) just before `lit`.
Returns: A `local_iterator<U>` to the beginning of the inserted range.

`c.erase(xit1)`
`c.erase(xit1,xit2)`

Effects: Erases the indicated element(s).
Returns: A non-const iterator of the same category as `xit` pointing to the position just after the erased element(s).
Complexity: Linear on the number of elements erased plus the distance from the last one to the end of its segment.

`c.clear()`

Effects: Erases all the elements of the container.
Complexity: Linear.

`c.clear(info)`
`c.clear<U>()`

Effects: Erases all the elements of the segment for the indicated type.
Complexity: Linear in the size of the segment.
Throws: If the indicated type is not registered.

### Header `"boost/poly_collection/exception.hpp"` synopsis

All the collections in Boost.PolyCollection use the following exceptions (and only these) to signal various run-time problems with contained types:

    namespace boost{

    namespace poly_collection{

    struct unregistered_type;
    struct not_copy_constructible;
    struct not_equality_comparable;

    } /* namespace poly_collection */

    } /* namespace boost */

#### Class `unregistered_type`

    struct unregistered_type:std::logic_error
    {
      unregistered_type(const std::type_info& info);

      const std::type_info* pinfo;
    };

`unregistered_type` is thrown when an operation is requested on a type which does not yet have an associated segment.

`unregistered_type(const std::type_info& info);`

Effects: Constructs an `unregistered_type` object with the specified type information.

#### Class `not_copy_constructible`

    struct not_copy_constructible:std::logic_error
    {
      not_copy_constructible(const std::type_info& info);

      const std::type_info* pinfo;
    };

`not_copy_constructible` is thrown when a copy operation is tried that involves a non-`CopyConstructible` type.

`not_copy_constructible(const std::type_info& info);`

Effects: Constructs a `not_copy_constructible` object with the specified type information.

#### Class `not_equality_comparable`

    struct not_equality_comparable:std::logic_error
    {
      not_equality_comparable(const std::type_info& info);

      const std::type_info* pinfo;
    };

`not_equality_comparable` is thrown when comparing two collections for (in)equality involves a non-`EqualityComparable` type.

`not_equality_comparable(const std::type_info& info);`

Effects: Constructs a `not_equality_comparable` object with the specified type information.

### Header `"boost/poly_collection/base_collection_fwd.hpp"` synopsis

    #include <memory>

    namespace boost{

    namespace poly_collection{

    template<typename Base,typename Allocator=std::allocator<Base>>
    class base_collection;

    template<typename Base,typename Allocator>
    bool operator==(
      const base_collection<Base,Allocator>& x,
      const base_collection<Base,Allocator>& y);

    template<typename Base,typename Allocator>
    bool operator!=(
      const base_collection<Base,Allocator>& x,
      const base_collection<Base,Allocator>& y);

    template<typename Base,typename Allocator>
    void swap(
      base_collection<Base,Allocator>& x,base_collection<Base,Allocator>& y);

    } /* namespace poly_collection */

    using poly_collection::base_collection;

    } /* namespace boost */

Forward declares the class template `base_collection` and specifies its default template arguments. Forward declares associated free functions and brings `boost::poly_collection::base_collection` to the `boost` namespace.

### Header `"boost/poly_collection/base_collection.hpp"` synopsis

    #include <boost/poly_collection/base_collection_fwd.hpp>

    namespace boost{

    namespace poly_collection{

    template<typename Base,typename Allocator>
    class base_collection;

    template<typename Base,typename Allocator>
    bool operator==(
      const base_collection<Base,Allocator>& x,
      const base_collection<Base,Allocator>& y);

    template<typename Base,typename Allocator>
    bool operator!=(
      const base_collection<Base,Allocator>& x,
      const base_collection<Base,Allocator>& y);

    template<typename Base,typename Allocator>
    void swap(
      base_collection<Base,Allocator>& x,base_collection<Base,Allocator>& y);

    } /* namespace poly_collection */

    } /* namespace boost */

#### Class template `base_collection`

`base_collection<Base,Allocator>` is an open `PolymorphicCollection` associated to the classic base/derived polymorphism model:

- Interface = { `Base` : `std::is_polymorphic_v<Base>` }.
- Implementation(`Base`) = { `Derived` : `std::is_base_of_v<Base,Derived>` }.
- subobject(`x`) = `static_cast<Derived&>(x)` with `typeid(x)==typeid(Derived)`.

    template<typename Base,typename Allocator>
    class base_collection
    {
    public:
      // types:

      using value_type=Base;
      using allocator_type=Allocator;
      using size_type=std::size_t;
      using difference_type=std::ptrdiff_t;
      using reference=value_type&;
      using const_reference=const value_type&;
      using pointer=typename std::allocator_traits<Allocator>::pointer;
      using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
      using type_index=std::type_info;
      using iterator=implementation-defined;
      using const_iterator=implementation-defined;
      using local_base_iterator=implementation-defined;
      using const_local_base_iterator=implementation-defined;
      template<typename T> using local_iterator=implementation-defined;
      template<typename T> using const_local_iterator=implementation-defined;
      class const_base_segment_info;
      class base_segment_info;
      template<typename T> class const_segment_info;
      template<typename T> class segment_info;
      using base_segment_info_iterator=implementation-defined;
      using const_base_segment_info_iterator=implementation-defined;
      class const_segment_traversal_info;
      class segment_traversal_info;

      // construct/destroy/copy:

      base_collection();
      base_collection(const base_collection&);
      base_collection(base_collection&&);
      explicit base_collection(const allocator_type& al);
      base_collection(const base_collection& x,const allocator_type& al);
      base_collection(base_collection&& x,const allocator_type& al);
      template<typename InputIterator>
      base_collection(
        InputIterator first,InputIterator last,
        const allocator_type& al=allocator_type{});

      base_collection& operator=(const base_collection&);
      base_collection& operator=(base_collection&&);

      allocator_type get_allocator()const noexcept;

      // type registration:

      template<typename... T>
      void register_types();

      bool is_registered(const type_index& info)const;
      template<typename T> bool is_registered()const;

      // iterators:

      iterator       begin()noexcept;
      iterator       end()noexcept;
      const_iterator begin()const noexcept;
      const_iterator end()const noexcept;
      const_iterator cbegin()const noexcept;
      const_iterator cend()const noexcept;

      local_base_iterator begin(const type_index& info);
      local_base_iterator end(const type_index& info);
      const_local_base_iterator begin(const type_index& info)const;
      const_local_base_iterator end(const type_index& info)const;
      const_local_base_iterator cbegin(const type_index& info)const;
      const_local_base_iterator cend(const type_index& info)const;

      template<typename T> local_iterator<T> begin();
      template<typename T> local_iterator<T> end();
      template<typename T> const_local_iterator<T> begin()const;
      template<typename T> const_local_iterator<T> end()const;
      template<typename T> const_local_iterator<T> cbegin()const;
      template<typename T> const_local_iterator<T> cend()const;

      base_segment_info       segment(const type_index& info);
      const_base_segment_info segment(const type_index& info)const;
      template<typename T> segment_info<T>       segment();
      template<typename T> const_segment_info<T> segment()const;

      segment_traversal_info       segment_traversal()noexcept;
      const_segment_traversal_info segment_traversal()const noexcept;

      // capacity:

      bool empty()const noexcept;
      bool empty(const type_index& info)const;
      template<typename T> bool empty()const;

      size_type size()const noexcept;
      size_type size(const type_index& info)const;
      template<typename T> size_type size()const;

      size_type max_size(const type_index& info)const;
      template<typename T> size_type max_size()const;

      size_type capacity(const type_index& info)const;
      template<typename T> size_type capacity()const;

      void reserve(size_type n);
      void reserve(const type_index& info,size_type n);
      template<typename T>void reserve(size_type n);

      void shrink_to_fit();
      void shrink_to_fit(const type_index& info);
      template<typename T> void shrink_to_fit();

      // modifiers:

      template<typename T,typename... Args>
      iterator emplace(Args&&... args);

      template<typename T,typename... Args>
      iterator emplace_hint(const_iterator hint,Args&&... args);

      template<typename T,typename LocalIterator,typename... Args>
      auto emplace_pos(LocalIterator pos,Args&&... args);

      template<typename T>
      iterator insert(T&& x);

      template<typename CollectionIterator,typename T>
      auto insert(CollectionIterator hint,T&& x);

      template<typename InputIterator>
      void insert(InputIterator first,InputIterator last);

      template<typename CollectionIterator,typename InputIterator>
      void insert(CollectionIterator hint,InputIterator first,InputIterator last);

      template<typename CollectionIterator>
      auto erase(CollectionIterator pos);

      template<typename CollectionIterator>
      auto erase(CollectionIterator first,CollectionIterator last);

      void clear()noexcept;
      void clear(const type_index& info);
      template<typename T> void clear();

      void swap(base_collection& x);
    };

### Header `"boost/poly_collection/function_collection_fwd.hpp"` synopsis

    #include <memory>

    namespace boost{

    namespace poly_collection{

    template<typename Signature>
    using function_collection_value_type=implementation-defined;

    template<
      typename Signature,
      typename Allocator=std::allocator<function_collection_value_type<Signature>>
    >
    class function_collection;

    template<typename Signature,typename Allocator>
    bool operator==(
      const function_collection<Signature,Allocator>& x,
      const function_collection<Signature,Allocator>& y);

    template<typename Signature,typename Allocator>
    bool operator!=(
      const function_collection<Signature,Allocator>& x,
      const function_collection<Signature,Allocator>& y);

    template<typename Signature,typename Allocator>
    void swap(
      function_collection<Signature,Allocator>& x,
      function_collection<Signature,Allocator>& y);

    } /* namespace poly_collection */

    using poly_collection::function_collection;

    } /* namespace boost */

Defines the alias template `function_collection_value_type` (the actual type it refers to, though, is merely forward declared). Forward declares the class template `function_collection` and specifies its default template arguments. Forward declares associated free functions and brings `boost::poly_collection::function_collection` to the `boost` namespace.

### Header `"boost/poly_collection/function_collection.hpp"` synopsis

    #include <boost/poly_collection/function_collection_fwd.hpp>

    namespace boost{

    namespace poly_collection{

    // defines the type function_collection_value_type refers to

    template<typename Signature,typename Allocator>
    class function_collection;

    template<typename Signature,typename Allocator>
    bool operator==(
      const function_collection<Signature,Allocator>& x,
      const function_collection<Signature,Allocator>& y);

    template<typename Signature,typename Allocator>
    bool operator!=(
      const function_collection<Signature,Allocator>& x,
      const function_collection<Signature,Allocator>& y);

    template<typename Signature,typename Allocator>
    void swap(
      function_collection<Signature,Allocator>& x,
      function_collection<Signature,Allocator>& y);

    } /* namespace poly_collection */

    } /* namespace boost */

#### Alias template `function_collection_value_type`

`function_collection_value_type<Signature>` is the `value_type` of `boost::function_collection<Signature,Allocator>`, where `Signature` must be a type of the form `R(Args...)`. `function_collection_value_type<Signature>` wraps a reference to an object modeling `Callable` for the given `Signature`. The interface provided partially replicates that of `std::function` and adds some extra facilities.

In what follows, the name `function_collection_value_type_impl` is used just for explanatory purposes in place of the actual class template name, which is implementation defined.

    template<typename Signature>
    using function_collection_value_type=
      function_collection_value_type_impl<Signature>;

    template<typename Signature>
    class function_collection_value_type_impl;

    template<typename R,typename... Args>
    class function_collection_value_type_impl<R(Args...)>
    {
    public:
      explicit operator bool()const noexcept;

      R operator()(Args... args)const;

      const std::type_info& target_type()const noexcept;
      template<typename T> T* target()noexcept;
      template<typename T> const T* target()const noexcept;

      operator std::function<R(Args...)>()const noexcept;

      void*       data()noexcept;
      const void* data()const noexcept;
    };

`explicit operator bool()const noexcept;`

Returns: `true`.

`R operator()(Args... args)const;`

Effects: ``INVOKE`(f,std::forward<Args>(args)...,R)`, where f is the wrapped callable object.
Returns: Nothing if `R` is `void`, otherwise the return value of ``INVOKE`(f,std::forward<Args>(args)...,R)`.

`const std::type_info& target_type()const noexcept;`

Returns: `typeid(T)` where `T` is the type of the wrapped callable object.

`template<typename T> T* target()noexcept;`
`template<typename T> const T* target()const noexcept;`

Returns: If `target_type()==typeid(T)` a pointer to the wrapped callable object, otherwise `nullptr`.

`operator std::function<R(Args...)>()const noexcept;`

Returns: A `std::function<R(Args...)>` object holding a reference to the wrapped callable object.

`void* data()noexcept;`
`const void* data()const noexcept;`

Returns: The address of the wrapped callable object.

#### Class template `function_collection`

`function_collection<Signature,Allocator>` is an open `PolymorphicCollection` associated to a dynamic polymorphism model based on call signature compatibility:

- Interface = { `Signature` : `Signature` = `R(Args...)` }.
- Implementation(`Signature`) = { `Callable` : `std::is_invocable_r_v<R,Callable,Args...>` }.
- subobject(`x`) =
  - `x.target<T>()` with `typeid(T)==x.target_type()`, if `x` is an instantiation of `function_collection_value_type`,
  - `x`, otherwise.

    template<typename Signature,typename Allocator>
    class function_collection
    {
    public:
      // types:

      using value_type=function_collection_value_type<Signature>;
      using allocator_type=Allocator;
      using size_type=std::size_t;
      using difference_type=std::ptrdiff_t;
      using reference=value_type&;
      using const_reference=const value_type&;
      using pointer=typename std::allocator_traits<Allocator>::pointer;
      using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
      using type_index=std::type_info;
      using iterator=implementation-defined;
      using const_iterator=implementation-defined;
      using local_base_iterator=implementation-defined;
      using const_local_base_iterator=implementation-defined;
      template<typename T> using local_iterator=implementation-defined;
      template<typename T> using const_local_iterator=implementation-defined;
      class const_base_segment_info;
      class base_segment_info;
      template<typename T> class const_segment_info;
      template<typename T> class segment_info;
      using base_segment_info_iterator=implementation-defined;
      using const_base_segment_info_iterator=implementation-defined;
      class const_segment_traversal_info;
      class segment_traversal_info;

      // construct/destroy/copy:

      function_collection();
      function_collection(const function_collection&);
      function_collection(function_collection&&);
      explicit function_collection(const allocator_type& al);
      function_collection(const function_collection& x,const allocator_type& al);
      function_collection(function_collection&& x,const allocator_type& al);
      template<typename InputIterator>
      function_collection(
        InputIterator first,InputIterator last,
        const allocator_type& al=allocator_type{});

      function_collection& operator=(const function_collection&);
      function_collection& operator=(function_collection&&);

      allocator_type get_allocator()const noexcept;

      // type registration:

      template<typename... T>
      void register_types();

      bool is_registered(const type_index& info)const;
      template<typename T> bool is_registered()const;

      // iterators:

      iterator       begin()noexcept;
      iterator       end()noexcept;
      const_iterator begin()const noexcept;
      const_iterator end()const noexcept;
      const_iterator cbegin()const noexcept;
      const_iterator cend()const noexcept;

      local_base_iterator begin(const type_index& info);
      local_base_iterator end(const type_index& info);
      const_local_base_iterator begin(const type_index& info)const;
      const_local_base_iterator end(const type_index& info)const;
      const_local_base_iterator cbegin(const type_index& info)const;
      const_local_base_iterator cend(const type_index& info)const;

      template<typename T> local_iterator<T> begin();
      template<typename T> local_iterator<T> end();
      template<typename T> const_local_iterator<T> begin()const;
      template<typename T> const_local_iterator<T> end()const;
      template<typename T> const_local_iterator<T> cbegin()const;
      template<typename T> const_local_iterator<T> cend()const;

      base_segment_info       segment(const type_index& info);
      const_base_segment_info segment(const type_index& info)const;
      template<typename T> segment_info<T>       segment();
      template<typename T> const_segment_info<T> segment()const;

      segment_traversal_info       segment_traversal()noexcept;
      const_segment_traversal_info segment_traversal()const noexcept;

      // capacity:

      bool empty()const noexcept;
      bool empty(const type_index& info)const;
      template<typename T> bool empty()const;

      size_type size()const noexcept;
      size_type size(const type_index& info)const;
      template<typename T> size_type size()const;

      size_type max_size(const type_index& info)const;
      template<typename T> size_type max_size()const;

      size_type capacity(const type_index& info)const;
      template<typename T> size_type capacity()const;

      void reserve(size_type n);
      void reserve(const type_index& info,size_type n);
      template<typename T>void reserve(size_type n);

      void shrink_to_fit();
      void shrink_to_fit(const type_index& info);
      template<typename T> void shrink_to_fit();

      // modifiers:

      template<typename T,typename... Args>
      iterator emplace(Args&&... args);

      template<typename T,typename... Args>
      iterator emplace_hint(const_iterator hint,Args&&... args);

      template<typename T,typename LocalIterator,typename... Args>
      auto emplace_pos(LocalIterator pos,Args&&... args);

      template<typename T>
      iterator insert(T&& x);

      template<typename CollectionIterator,typename T>
      auto insert(CollectionIterator hint,T&& x);

      template<typename InputIterator>
      void insert(InputIterator first,InputIterator last);

      template<typename CollectionIterator,typename InputIterator>
      void insert(CollectionIterator hint,InputIterator first,InputIterator last);

      template<typename CollectionIterator>
      auto erase(CollectionIterator pos);

      template<typename CollectionIterator>
      auto erase(CollectionIterator first,CollectionIterator last);

      void clear()noexcept;
      void clear(const type_index& info);
      template<typename T> void clear();

      void swap(function_collection& x);
    };

### Header `"boost/poly_collection/any_collection_fwd.hpp"` synopsis

    #include <memory>

    namespace boost{

    namespace poly_collection{

    template<typename Concept>
    using any_collection_value_type=implementation-defined;

    template<
      typename Concept,
      typename Allocator=std::allocator<any_collection_value_type<Concept>>
    >
    class any_collection;

    template<typename Concept,typename Allocator>
    bool operator==(
      const any_collection<Concept,Allocator>& x,
      const any_collection<Concept,Allocator>& y);

    template<typename Concept,typename Allocator>
    bool operator!=(
      const any_collection<Concept,Allocator>& x,
      const any_collection<Concept,Allocator>& y);

    template<typename Concept,typename Allocator>
    void swap(
      any_collection<Concept,Allocator>& x,any_collection<Concept,Allocator>& y);

    } /* namespace poly_collection */

    using poly_collection::any_collection;

    } /* namespace boost */

Defines the alias template `any_collection_value_type` (the actual type it refers to, though, is merely forward declared). Forward declares the class template `any_collection` and specifies its default template arguments. Forward declares associated free functions and brings `boost::poly_collection::any_collection` to the `boost` namespace.

### Header `"boost/poly_collection/any_collection.hpp"` synopsis

    #include <boost/poly_collection/any_collection_fwd.hpp>

    namespace boost{

    namespace poly_collection{

    // defines the type any_collection_value_type refers to

    template<typename Concept,typename Allocator>
    class any_collection;

    template<typename Concept,typename Allocator>
    bool operator==(
      const any_collection<Concept,Allocator>& x,
      const any_collection<Concept,Allocator>& y);

    template<typename Concept,typename Allocator>
    bool operator!=(
      const any_collection<Concept,Allocator>& x,
      const any_collection<Concept,Allocator>& y);

    template<typename Concept,typename Allocator>
    void swap(
      any_collection<Concept,Allocator>& x,any_collection<Concept,Allocator>& y);

    } /* namespace poly_collection */

    } /* namespace boost */

#### Alias template `any_collection_value_type`

`any_collection_value_type<Concept>` is the `value_type` of `boost::any_collection<Concept,Allocator>`, where `Concept` is defined according to the requisites of Boost.TypeErasure using `_self` as its placeholder. The alias template definition has the form

    template<typename Concept>
    using any_collection_value_type=
      boost::type_erasure::any<Concept2,boost::type_erasure::_self&>;

with `boost::type_erasure::``is_subconcept``<Concept,Concept2>::value==true`. The exact definition of `Concept2` is implementation defined.

#### Class template `any_collection`

`any_collection<Concept,Allocator>` is an open `PolymorphicCollection` associated to a dynamic polymorphism model based on duck typing as implemented by Boost.TypeErasure:

- Interface = { `Concept` : as specified by Boost.TypeErasure, using the `_self` placeholder }.
- Implementation(`Concept`) = { `Concrete` : `Concrete` satisfies `Concept` }.
- subobject(`x`) =
  - `boost::type_erasure::``any_cast``<T&>(x)` with `typeid(T)==boost::type_erasure::``typeid_of``(x)`, if `x` is an instantiation of `boost::type_erasure::``any` including `typeid_``<>`,
  - `x`, otherwise.

    template<typename Concept,typename Allocator>
    class any_collection
    {
    public:
      // types:

      using value_type=any_collection_value_type<Concept>;
      using allocator_type=Allocator;
      using size_type=std::size_t;
      using difference_type=std::ptrdiff_t;
      using reference=value_type&;
      using const_reference=const value_type&;
      using pointer=typename std::allocator_traits<Allocator>::pointer;
      using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
      using type_index=std::type_info;
      using iterator=implementation-defined;
      using const_iterator=implementation-defined;
      using local_base_iterator=implementation-defined;
      using const_local_base_iterator=implementation-defined;
      template<typename T> using local_iterator=implementation-defined;
      template<typename T> using const_local_iterator=implementation-defined;
      class const_base_segment_info;
      class base_segment_info;
      template<typename T> class const_segment_info;
      template<typename T> class segment_info;
      using base_segment_info_iterator=implementation-defined;
      using const_base_segment_info_iterator=implementation-defined;
      class const_segment_traversal_info;
      class segment_traversal_info;

      // construct/destroy/copy:

      any_collection();
      any_collection(const any_collection&);
      any_collection(any_collection&&);
      explicit any_collection(const allocator_type& al);
      any_collection(const any_collection& x,const allocator_type& al);
      any_collection(any_collection&& x,const allocator_type& al);
      template<typename InputIterator>
      any_collection(
        InputIterator first,InputIterator last,
        const allocator_type& al=allocator_type{});

      any_collection& operator=(const any_collection&);
      any_collection& operator=(any_collection&&);

      allocator_type get_allocator()const noexcept;

      // type registration:

      template<typename... T>
      void register_types();

      bool is_registered(const type_index& info)const;
      template<typename T> bool is_registered()const;

      // iterators:

      iterator       begin()noexcept;
      iterator       end()noexcept;
      const_iterator begin()const noexcept;
      const_iterator end()const noexcept;
      const_iterator cbegin()const noexcept;
      const_iterator cend()const noexcept;

      local_base_iterator begin(const type_index& info);
      local_base_iterator end(const type_index& info);
      const_local_base_iterator begin(const type_index& info)const;
      const_local_base_iterator end(const type_index& info)const;
      const_local_base_iterator cbegin(const type_index& info)const;
      const_local_base_iterator cend(const type_index& info)const;

      template<typename T> local_iterator<T> begin();
      template<typename T> local_iterator<T> end();
      template<typename T> const_local_iterator<T> begin()const;
      template<typename T> const_local_iterator<T> end()const;
      template<typename T> const_local_iterator<T> cbegin()const;
      template<typename T> const_local_iterator<T> cend()const;

      base_segment_info       segment(const type_index& info);
      const_base_segment_info segment(const type_index& info)const;
      template<typename T> segment_info<T>       segment();
      template<typename T> const_segment_info<T> segment()const;

      segment_traversal_info       segment_traversal()noexcept;
      const_segment_traversal_info segment_traversal()const noexcept;

      // capacity:

      bool empty()const noexcept;
      bool empty(const type_index& info)const;
      template<typename T> bool empty()const;

      size_type size()const noexcept;
      size_type size(const type_index& info)const;
      template<typename T> size_type size()const;

      size_type max_size(const type_index& info)const;
      template<typename T> size_type max_size()const;

      size_type capacity(const type_index& info)const;
      template<typename T> size_type capacity()const;

      void reserve(size_type n);
      void reserve(const type_index& info,size_type n);
      template<typename T>void reserve(size_type n);

      void shrink_to_fit();
      void shrink_to_fit(const type_index& info);
      template<typename T> void shrink_to_fit();

      // modifiers:

      template<typename T,typename... Args>
      iterator emplace(Args&&... args);

      template<typename T,typename... Args>
      iterator emplace_hint(const_iterator hint,Args&&... args);

      template<typename T,typename LocalIterator,typename... Args>
      auto emplace_pos(LocalIterator pos,Args&&... args);

      template<typename T>
      iterator insert(T&& x);

      template<typename CollectionIterator,typename T>
      auto insert(CollectionIterator hint,T&& x);

      template<typename InputIterator>
      void insert(InputIterator first,InputIterator last);

      template<typename CollectionIterator,typename InputIterator>
      void insert(CollectionIterator hint,InputIterator first,InputIterator last);

      template<typename CollectionIterator>
      auto erase(CollectionIterator pos);

      template<typename CollectionIterator>
      auto erase(CollectionIterator first,CollectionIterator last);

      void clear()noexcept;
      void clear(const type_index& info);
      template<typename T> void clear();

      void swap(any_collection& x);
    };

### Header `"boost/poly_collection/variant_collection_fwd.hpp"` synopsis

    #include <boost/mp11/list.hpp>
    #include <memory>

    namespace boost{

    namespace poly_collection{

    template<typename TypeList>
    using variant_collection_value_type=implementation-defined;

    template<
      typename TypeList,
      typename Allocator=std::allocator<variant_collection_value_type<TypeList>>
    >
    class variant_collection;

    template<typename... Ts>
    using variant_collection_of=variant_collection<mp11::mp_list<Ts...>>;

    template<typename TypeList,typename Allocator>
    bool operator==(
      const variant_collection<TypeList,Allocator>& x,
      const variant_collection<TypeList,Allocator>& y);

    template<typename TypeList,typename Allocator>
    bool operator!=(
      const variant_collection<TypeList,Allocator>& x,
      const variant_collection<TypeList,Allocator>& y);

    template<typename TypeList,typename Allocator>
    void swap(
      variant_collection<TypeList,Allocator>& x,variant_collection<TypeList,Allocator>& y);

    } /* namespace poly_collection */

    using poly_collection::variant_collection;
    using poly_collection::variant_collection_of;

    } /* namespace boost */

Defines the alias template `variant_collection_value_type` (the actual type it refers to, though, is merely forward declared). Forward declares the class template `variant_collection` and specifies its default template arguments. Defines the alias template `variant_collection_of`. Forward declares associated free functions and brings `boost::poly_collection::variant_collection` and `poly_collection::variant_collection_of` to the `boost` namespace.

### Header `"boost/poly_collection/variant_collection.hpp"` synopsis

    #include <boost/poly_collection/variant_collection_fwd.hpp>

    namespace boost{

    namespace poly_collection{

    // defines the type variant_collection_value_type refers to

    template<typename TypeList,typename Allocator>
    class variant_collection;

    template<typename TypeList,typename Allocator>
    bool operator==(
      const variant_collection<TypeList,Allocator>& x,
      const variant_collection<TypeList,Allocator>& y);

    template<typename TypeList,typename Allocator>
    bool operator!=(
      const variant_collection<TypeList,Allocator>& x,
      const variant_collection<TypeList,Allocator>& y);

    template<typename TypeList,typename Allocator>
    void swap(
      variant_collection<TypeList,Allocator>& x,variant_collection<TypeList,Allocator>& y);

    } /* namespace poly_collection */

    } /* namespace boost */

#### Alias template `variant_collection_value_type`

`variant_collection_value_type<TypeList>` is the `value_type` of `boost::variant_collection<TypeList,Allocator>`, where `TypeList` is a Boost.Mp11 list of different types `Ts...`. `variant_collection_value_type<TypeList>` behaves similarly to `std::variant``<Ts...>`, with some intentional limitations such as the impossibility of changing the type of the underlying alternative.

In what follows, the name `variant_collection_value_type_impl` is used just for explanatory purposes in place of the actual class template name, which is implementation defined.

    template<typename TypeList>
    using variant_collection_value_type=
      mp11::mp_rename<TypeList,variant_collection_value_type_impl>;

    template<typename... Ts>
    class variant_collection_value_type_impl
    {
    public:
      // copy and assigmnent are disallowed

      std::size_t index()const noexcept;
      bool        valueless_by_exception()const noexcept;
    };

    struct bad_variant_access:std::exception
    {
      bad_variant_access()noexcept{}
      const char* what()const noexcept;
    };

    template<typename V> struct variant_size; // not defined
    template<typename... Ts>
    struct variant_size<variant_collection_value_type_impl<Ts...>>;
    template<typename V> struct variant_size<const V>;

    template<typename V>
    constexpr std::size_t variant_size_v=variant_size<V>::value;

    template<std::size_t I,typename T> struct variant_alternative; // not defined
    template<std::size_t I,typename... Ts>
    struct variant_alternative<I,variant_collection_value_type_impl<Ts...>>;
    template<std::size_t I,typename V> struct variant_alternative<I,const T>;
    template<std::size_t I,typename V> struct variant_alternative<I,V&>;
    template<std::size_t I,typename V> struct variant_alternative<I,const V&>;
    template<std::size_t I,typename V> struct variant_alternative<I,V&&>;
    template<std::size_t I,typename V> struct variant_alternative<I,const V&&>;

    template<std::size_t I,typename V>
    using variant_alternative_t=typename variant_alternative<I,V>::type;

    template<typename T,typename... Ts>
    bool holds_alternative(const variant_collection_value_type_impl<Ts...>& x)noexcept;

    template<std::size_t I,typename V>
    variant_alternative_t<I,V&&> get(V&& x);

    template<typename T,typename V>
    variant_alternative_t<mp11::mp_find<std::decay_t<V>,T>::value,V&&> get(V&& x);

    template<std::size_t I,typename... Ts>
    variant_alternative_t<I,variant_collection_value_type_impl<Ts...>>*
    get_if(variant_collection_value_type_impl<Ts...>* px)noexcept;
    template<std::size_t I,typename... Ts>
    const variant_alternative_t<I,variant_collection_value_type_impl<Ts...>>*
    get_if(const variant_collection_value_type_impl<Ts...>* px)noexcept;

    template<typename T,typename... Ts>
    T* get_if(variant_collection_value_type_impl<Ts...>* px)noexcept;
    template<typename T,typename... Ts>
    const T* get_if(const variant_collection_value_type_impl<Ts...>* px)noexcept;

    template<typename... Ts>
    bool operator==(
      const variant_collection_value_type_impl<Ts...>& x,
      const variant_collection_value_type_impl<Ts...>& y);
    template<typename... Ts>
    bool operator!=(
      const variant_collection_value_type_impl<Ts...>& x,
      const variant_collection_value_type_impl<Ts...>& y);
    template<typename... Ts>
    bool operator<(
      const variant_collection_value_type_impl<Ts...>& x,
      const variant_collection_value_type_impl<Ts...>& y);
    template<typename... Ts>
    bool operator>(
      const variant_collection_value_type_impl<Ts...>& x,
      const variant_collection_value_type_impl<Ts...>& y);
    template<typename... Ts>
    bool operator=<(
      const variant_collection_value_type_impl<Ts...>& x,
      const variant_collection_value_type_impl<Ts...>& y);
    template<typename... Ts>
    bool operator>=(
      const variant_collection_value_type_impl<Ts...>& x,
      const variant_collection_value_type_impl<Ts...>& y);

    template<typename R=see-below,typename F,typename... Vs>
    see-below visit(F&& f,Vs&&... xs);

    template<typename R=see-below,typename V,typename... Fs>
    see-below visit_by_index(V&& x,Fs&&... fs);

`std::size_t index()const noexcept;`

Returns: The index number into `Ts...` of the type of the alternative contained in the variant.

`bool valueless_by_exception()const noexcept;`

Returns: `false`.

`template<typename... Ts>`
`struct variant_size<``variant_collection_value_type_impl``<Ts...>>;`
`template<typename V> struct variant_size<const V>;`

`variant_size<...>::value` is a `constexpr std::size_t` value with the number of alternative types specified for the variant.

`template<std::size_t I,typename... Ts>`
`struct variant_alternative<I,` `variant_collection_value_type_impl``<Ts...>>;`
`template<std::size_t I,typename V> struct variant_alternative<I,const T>;`
`template<std::size_t I,typename V> struct variant_alternative<I,V&>;`
`template<std::size_t I,typename V> struct variant_alternative<I,const V&>;`
`template<std::size_t I,typename V> struct variant_alternative<I,V&&>;`
`template<std::size_t I,typename V> struct variant_alternative<I,const V&&>;`

`variant_alternative<I,V>::type` is the `I`-th alternative type in the variant with the same `const` and reference qualification as `V`.

`template<typename T,typename... Ts>`
`bool holds_alternative(const` `variant_collection_value_type_impl``<Ts...>& x)noexcept;`

Returns: `true` iff the type of the alternative contained in the variant is `T`.

`template<std::size_t I,typename V>`
`variant_alternative_t<I,V&&> get(V&& x);`

Effects: Throws `bad_variant_access` if `x.index()!=I`.
Returns: A reference to the contained value with the same `const` and reference qualification as `x`.

`template<typename T,typename V>`
`variant_alternative_t<mp11::mp_find<std::decay_t<V>,T>::value,V&&> get(V&& x);`

Effects: Throws `bad_variant_access` if `!holds_alternative<T>(x)`.
Returns: A reference to the contained value with the same `const` and reference qualification as `x`.

`template<std::size_t I,typename... Ts>`
`variant_alternative_t<I,` `variant_collection_value_type_impl``<Ts...>>*`
`get_if(``variant_collection_value_type_impl``<Ts...>* px)noexcept;`
`template<std::size_t I,typename... Ts>`
`const variant_alternative_t<I,` `variant_collection_value_type_impl``<Ts...>>*`
`get_if(const` `variant_collection_value_type_impl``<Ts...>* px)noexcept;`

Returns: `nullptr` if `px` is null or `px->index()!=I`, a pointer to the contained value otherwise.

`template<typename T,typename... Ts>`
`T* get_if(``variant_collection_value_type_impl``<Ts...>* px)noexcept;`
`template<typename T,typename... Ts>`
`const T* get_if(const` `variant_collection_value_type_impl``<Ts...>* px)noexcept;`

Returns: `nullptr` if `px` is null or `!holds_alternative<T>(*px)`, a pointer to the contained value otherwise.

`template<typename... Ts>`
`bool operator==(`
`` `const` `variant_collection_value_type_impl``<Ts...>& x,`
`` `const` `variant_collection_value_type_impl``<Ts...>& y);`

Constraints: `std::declval<const Ti&>()==std::declval<const Ti&>()` is a valid expression convertible to `bool` for all `Ti` in `Ts...`.
Returns: `x.index()==y.index()&&get<I>(x)==get<I>(y)` with `I==x.index()`.

`template<typename... Ts>`
`bool operator!=(`
`` `const` `variant_collection_value_type_impl``<Ts...>& x,`
`` `const` `variant_collection_value_type_impl``<Ts...>& y);`

Constraints: `std::declval<const Ti&>()!=std::declval<const Ti&>()` is a valid expression convertible to `bool` for all `Ti` in `Ts...`.
Returns: `x.index()!=y.index()||get<I>(x)!=get<I>(y)` with `I==x.index()`.

`template<typename... Ts>`
`bool operator<(`
`` `const` `variant_collection_value_type_impl``<Ts...>& x,`
`` `const` `variant_collection_value_type_impl``<Ts...>& y);`

Constraints: `std::declval<const Ti&>()<std::declval<const Ti&>()` is a valid expression convertible to `bool` for all `Ti` in `Ts...`.
Returns: `x.index()<y.index()||x.index()==y.index()&&get<I>(x)<get<I>(y)` with `I==x.index()`.

`template<typename... Ts>`
`bool operator>(`
`` `const` `variant_collection_value_type_impl``<Ts...>& x,`
`` `const` `variant_collection_value_type_impl``<Ts...>& y);`

Constraints: `std::declval<const Ti&>()>std::declval<const Ti&>()` is a valid expression convertible to `bool` for all `Ti` in `Ts...`.
Returns: `x.index()>y.index()||x.index()==y.index()&&get<I>(x)>get<I>(y)` with `I==x.index()`.

`template<typename... Ts>`
`bool operator<=(`
`` `const` `variant_collection_value_type_impl``<Ts...>& x,`
`` `const` `variant_collection_value_type_impl``<Ts...>& y);`

Constraints: `std::declval<const Ti&>()<=std::declval<const Ti&>()` is a valid expression convertible to `bool` for all `Ti` in `Ts...`.
Returns: `x.index()<y.index()||x.index()==y.index()&&get<I>(x)<=get<I>(y)` with `I==x.index()`.

`template<typename... Ts>`
`bool operator>=(`
`` `const` `variant_collection_value_type_impl``<Ts...>& x,`
`` `const` `variant_collection_value_type_impl``<Ts...>& y);`

Constraints: `std::declval<const Ti&>()>=std::declval<const Ti&>()` is a valid expression convertible to `bool` for all `Ti` in `Ts...`.
Returns: `x.index()>y.index()||x.index()==y.index()&&get<I>(x)>=get<I>(y)` with `I==x.index()`.

`template<typename R=``see-below``,typename F,typename... Vs>`
`see-below` `visit(F&& f,Vs&&... xs);`

Effects: Calls the expression `e(Is...)`, defined as `std::forward<F>(f)(get<Is>(std::forward<Vs>(xs)...)`, with `Is...` equal to `xs.index()...`.
Returns:

- If `R` is specified as `void`: nothing.
- If `R` is specified as a type different from `void`: the value `e(Is...)` implicitly converted to `R`.
- If `R` is not specified, `e(Is...)`. In this and the previous case, `e(Js...)` must have the same type for all valid index packs `Js...`.

`template<typename R=``see-below``,typename V,typename... Fs>`
`see-below` `visit_by_index(V&& x,Fs&&... fs);`

Requires: `sizeof...(Fs)` is equal to the number of alternative types in the variant.
Effects: Calls the expression `e(i)`, defined as `std::forward<Fi>(fi)(get<i>(std::forward<V>(x)))`, with `i==x.index()` and `Fi` and `fi` denoting the `i`-th element of `Fs...` and `fs...`, respectively.
Returns:

- If `R` is specified as `void`: nothing.
- If `R` is specified as a type different from `void`: the value `e(i)` implicitly converted to `R`.
- If `R` is not specified, `e(i)`. In this and the previous case, `e(j)` must have the same type for all `j` in [0, `sizeof...(Fs)`).

#### Class template `variant_collection`

`variant_collection<TypeList,Allocator>` is a closed `PolymorphicCollection` associated to a dynamic polymorphism model based on the interface of `std::variant`:

- Interface = { `TypeList` = `L<Ts...>` : `L` is an arbitrary class template, `Ts...` is not empty, and each `Ti` in `Ts...` is different, `MoveConstructible`, and `MoveAssignable` or such that `std::is_nothrow_move_constructible<Ti>::value` is `true` }.
- Implementation(`L<Ts...>`) = { `Ts...` } ∪ { `variant_collection_value_type``<Us...>` : `Us...` ⊆ `Ts...` } ∪ { `std::variant``<Us...>` : `Us...` ⊆ `Ts...` } ∪ { `boost::variant2::variant``<Us...>` : `Us...` ⊆ `Ts...` }.
- subobject(`x`) =
  - `get<I>(x)` with `I==x.index()`, if the type of `x` is not in `Ts...`,
  - `x`, otherwise.

    template<typename TypeList,typename Allocator>
    class variant_collection
    {
    public:
      // types:

      using value_type=variant_collection_value_type<TypeList>;
      using allocator_type=Allocator;
      using size_type=std::size_t;
      using difference_type=std::ptrdiff_t;
      using reference=value_type&;
      using const_reference=const value_type&;
      using pointer=typename std::allocator_traits<Allocator>::pointer;
      using const_pointer=typename std::allocator_traits<Allocator>::const_pointer;
      using type_index=std::size_t;
      using iterator=implementation-defined;
      using const_iterator=implementation-defined;
      using local_base_iterator=implementation-defined;
      using const_local_base_iterator=implementation-defined;
      template<typename T> using local_iterator=implementation-defined;
      template<typename T> using const_local_iterator=implementation-defined;
      class const_base_segment_info;
      class base_segment_info;
      template<typename T> class const_segment_info;
      template<typename T> class segment_info;
      using base_segment_info_iterator=implementation-defined;
      using const_base_segment_info_iterator=implementation-defined;
      class const_segment_traversal_info;
      class segment_traversal_info;

      // construct/destroy/copy:

      variant_collection();
      variant_collection(const variant_collection&);
      variant_collection(variant_collection&&);
      explicit variant_collection(const allocator_type& al);
      variant_collection(const variant_collection& x,const allocator_type& al);
      variant_collection(variant_collection&& x,const allocator_type& al);
      template<typename InputIterator>
      variant_collection(
        InputIterator first,InputIterator last,
        const allocator_type& al=allocator_type{});

      variant_collection& operator=(const variant_collection&);
      variant_collection& operator=(variant_collection&&);

      allocator_type get_allocator()const noexcept;

      // iterators:

      iterator       begin()noexcept;
      iterator       end()noexcept;
      const_iterator begin()const noexcept;
      const_iterator end()const noexcept;
      const_iterator cbegin()const noexcept;
      const_iterator cend()const noexcept;

      local_base_iterator begin(const type_index& info);
      local_base_iterator end(const type_index& info);
      const_local_base_iterator begin(const type_index& info)const;
      const_local_base_iterator end(const type_index& info)const;
      const_local_base_iterator cbegin(const type_index& info)const;
      const_local_base_iterator cend(const type_index& info)const;

      template<typename T> local_iterator<T> begin();
      template<typename T> local_iterator<T> end();
      template<typename T> const_local_iterator<T> begin()const;
      template<typename T> const_local_iterator<T> end()const;
      template<typename T> const_local_iterator<T> cbegin()const;
      template<typename T> const_local_iterator<T> cend()const;

      base_segment_info       segment(const type_index& info);
      const_base_segment_info segment(const type_index& info)const;
      template<typename T> segment_info<T>       segment();
      template<typename T> const_segment_info<T> segment()const;

      segment_traversal_info       segment_traversal()noexcept;
      const_segment_traversal_info segment_traversal()const noexcept;

      // capacity:

      bool empty()const noexcept;
      bool empty(const type_index& info)const;
      template<typename T> bool empty()const;

      size_type size()const noexcept;
      size_type size(const type_index& info)const;
      template<typename T> size_type size()const;

      size_type max_size(const type_index& info)const;
      template<typename T> size_type max_size()const;

      size_type capacity(const type_index& info)const;
      template<typename T> size_type capacity()const;

      void reserve(size_type n);
      void reserve(const type_index& info,size_type n);
      template<typename T>void reserve(size_type n);

      void shrink_to_fit();
      void shrink_to_fit(const type_index& info);
      template<typename T> void shrink_to_fit();

      // modifiers:

      template<typename T,typename... Args>
      iterator emplace(Args&&... args);

      template<typename T,typename... Args>
      iterator emplace_hint(const_iterator hint,Args&&... args);

      template<typename T,typename LocalIterator,typename... Args>
      auto emplace_pos(LocalIterator pos,Args&&... args);

      template<typename T>
      iterator insert(T&& x);

      template<typename CollectionIterator,typename T>
      auto insert(CollectionIterator hint,T&& x);

      template<typename InputIterator>
      void insert(InputIterator first,InputIterator last);

      template<typename CollectionIterator,typename InputIterator>
      void insert(CollectionIterator hint,InputIterator first,InputIterator last);

      template<typename CollectionIterator>
      auto erase(CollectionIterator pos);

      template<typename CollectionIterator>
      auto erase(CollectionIterator first,CollectionIterator last);

      void clear()noexcept;
      void clear(const type_index& info);
      template<typename T> void clear();

      void swap(variant_collection& x);
    };

### Header `"boost/poly_collection/algorithm.hpp"` synopsis

    namespace boost{

    namespace poly_collection{

    // total restitution for closed collections:

    struct all_types;

    // non-modifying sequence operations:

    template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
    bool all_of(
      PolyCollectionIterator first,PolyCollectionIterator last,Predicate pred);

    template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
    bool any_of(
      PolyCollectionIterator first,PolyCollectionIterator last,Predicate pred);

    template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
    bool none_of(
      PolyCollectionIterator first,PolyCollectionIterator last,Predicate pred);

    template<typename... Ts,typename PolyCollectionIterator,typename Function>
    Function for_each(
      PolyCollectionIterator first,PolyCollectionIterator last,Function f);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename Size,typename Function
    >
    Iterator for_each_n(
      PolyCollectionIterator first,Size n,Function f);

    template<typename... Ts,typename PolyCollectionIterator,typename T>
    PolyCollectionIterator find(
      PolyCollectionIterator first,PolyCollectionIterator last,const T& x);

    template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
    PolyCollectionIterator find_if(
      PolyCollectionIterator first,PolyCollectionIterator last,Predicate pred);

    template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
    PolyCollectionIterator find_if_not(
      PolyCollectionIterator first,PolyCollectionIterator last,Predicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename ForwardIterator
    >
    PolyCollectionIterator find_end(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2,ForwardIterator last2);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename ForwardIterator,typename BinaryPredicate
    >
    PolyCollectionIterator find_end(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename ForwardIterator
    >
    PolyCollectionIterator find_first_of(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2,ForwardIterator last2);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename ForwardIterator,typename BinaryPredicate
    >
    PolyCollectionIterator find_first_of(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred);

    template<typename... Ts,typename PolyCollectionIterator>
    PolyCollectionIterator adjacent_find(
      PolyCollectionIterator first,PolyCollectionIterator last);

    template<
      typename... Ts,typename PolyCollectionIterator,typename BinaryPredicate
    >
    PolyCollectionIterator adjacent_find(
      PolyCollectionIterator first,PolyCollectionIterator last,
      BinaryPredicate pred);

    template<typename... Ts,typename PolyCollectionIterator,typename T>
    std::ptrdiff_t count(
      PolyCollectionIterator first,PolyCollectionIterator last,const T& x);

    template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
    std::ptrdiff_t count_if(
      PolyCollectionIterator first,PolyCollectionIterator last,Predicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename InputIterator
    >
    std::pair<PolyCollectionIterator,InputIterator> mismatch(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      InputIterator first2);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename InputIterator,typename BinaryPredicate
    >
    std::pair<PolyCollectionIterator,InputIterator> mismatch(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      InputIterator first2,BinaryPredicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename InputIterator
    >
    std::pair<PolyCollectionIterator,InputIterator> mismatch(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      InputIterator first2,InputIterator last2);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename InputIterator,typename BinaryPredicate
    >
    std::pair<PolyCollectionIterator,InputIterator> mismatch(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      InputIterator first2,InputIterator last2,BinaryPredicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename InputIterator
    >
    bool equal(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      InputIterator first2);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename InputIterator,typename BinaryPredicate
    >
    bool equal(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      InputIterator first2,BinaryPredicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename InputIterator
    >
    bool equal(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      InputIterator first2,InputIterator last2);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename InputIterator,typename BinaryPredicate
    >
    bool equal(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      InputIterator first2,InputIterator last2,BinaryPredicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename ForwardIterator
    >
    bool is_permutation(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename ForwardIterator,typename BinaryPredicate
    >
    bool is_permutation(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2,BinaryPredicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename ForwardIterator
    >
    bool is_permutation(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2,ForwardIterator last2);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename ForwardIterator,typename BinaryPredicate
    >
    bool is_permutation(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename ForwardIterator
    >
    PolyCollectionIterator search(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2,ForwardIterator last2);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename ForwardIterator,typename BinaryPredicate
    >
    PolyCollectionIterator search(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      ForwardIterator first2,ForwardIterator last2,BinaryPredicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename Size,typename T
    >
    PolyCollectionIterator search_n(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      Size count,const T& x);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename Size,typename T,typename BinaryPredicate
    >
    PolyCollectionIterator search_n(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      Size count,const T& x,BinaryPredicate pred);

    // modifying sequence operations:

    template<
      typename... Ts,typename PolyCollectionIterator,typename OutputIterator
    >
    OutputIterator copy(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename Size,typename OutputIterator
    >
    OutputIterator copy_n(
      PolyCollectionIterator first,Size count,OutputIterator res);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename OutputIterator,typename Predicate
    >
    OutputIterator copy_if(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res,Predicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename OutputIterator
    >
    OutputIterator move(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename OutputIterator,typename UnaryOperation
    >
    OutputIterator transform(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res,UnaryOperation op);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename InputIterator,typename OutputIterator,typename BinaryOperation
    >
    OutputIterator transform(
      PolyCollectionIterator first1,PolyCollectionIterator last1,
      InputIterator first2,OutputIterator res,BinaryOperation op);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename OutputIterator,typename T
    >
    OutputIterator replace_copy(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res,const T& old_x,const T& new_x);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename OutputIterator,typename Predicate,typename T
    >
    OutputIterator replace_copy_if(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res,Predicate pred,const T& new_x);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename OutputIterator,typename T
    >
    OutputIterator remove_copy(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res,const T& x);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename OutputIterator,typename Predicate
    >
    OutputIterator remove_copy_if(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res,Predicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename OutputIterator
    >
    OutputIterator unique_copy(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename OutputIterator,typename BinaryPredicate
    >
    OutputIterator unique_copy(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res,BinaryPredicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,typename OutputIterator
    >
    OutputIterator rotate_copy(
      PolyCollectionIterator first,PolyCollectionIterator middle,
      PolyCollectionIterator last,OutputIterator res);

    template<
      typename... Ts,typename PolyCollectionIterator,typename OutputIterator,
      typename Distance,typename UniformRandomBitGenerator
    >
    OutputIterator sample(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator res,Distance n,UniformRandomBitGenerator&& g);

    template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
    bool is_partitioned(
      PolyCollectionIterator first,PolyCollectionIterator last,Predicate pred);

    template<
      typename... Ts,typename PolyCollectionIterator,
      typename OutputIterator1,typename OutputIterator2,typename Predicate
    >
    std::pair<OutputIterator1,OutputIterator2> partition_copy(
      PolyCollectionIterator first,PolyCollectionIterator last,
      OutputIterator1 rest,OutputIterator2 resf,Predicate pred);

    template<typename... Ts,typename PolyCollectionIterator,typename Predicate>
    PolyCollectionIterator partition_point(
      PolyCollectionIterator first,PolyCollectionIterator last,Predicate pred);

    } /* namespace poly_collection */

    } /* namespace boost */

The algorithms provided mimic the functionality of their homonyms in `<algorithm>` but take advantage of the segmented nature of Boost.PolyCollection (global) iterators to deliver better performance. Additionally, concrete types can be passed to these algorithms for type restitution.

For the description of the algorithms we use the following notation:

- `alg` is the (unqualified) name of any of the algorithms in `"boost/poly_collection/algorithm.hpp"` except `for_each_n`, `copy_n` and `rotate_copy`.
- `first`, `middle` and `last` are (same-typed) possibly const global iterators of a collection of Boost.PolyCollection such that [`first`, `middle`) and [`middle`, `last`) are valid ranges.
- `args...` is a function parameter pack of types `Args&&...`,
- `Ts...` is a template parameter pack of acceptable types for the collection, plus optionally `all_types` in the case of closed collections.
  - Open collections: `Us...` is defined as `Ts...`.
  - Closed collections: `Us...` is defined as the set of all acceptable types in the collection if `all_types` is in `Ts...`, or as `Ts...` otherwise.

(1) `alg``(first,last,args...)`
(2) `for_each_n(first,args...)`
(3) `copy_n(first,args...)`
(4) `rotate_copy(first,middle,last,args...)`

Requires: The expression `expr` is well-formed, where `expr` is defined as:
(1) `std::``alg``(first,last,args...)`,
(2) `std::for_each_n(first,args...)`,
(3) `std::copy_n(first,args...)`,
(4) `std::rotate_copy(first,middle,last,args...)`.
Effects: Equivalent to `expr`.
Returns: `expr`.
Complexity: That of `expr`.

(1) `alg``<Ts...>(first,last,args...)`
(2) `for_each_n<Ts...>(first,args...)`
(3) `copy_n<Ts...>(first,args...)`
(4) `rotate_copy<Ts...>(first,middle,last,args...)`

Requires: The expression `expr` is well-formed, where `expr` is defined as:
(1) `std::``alg``(rfirst,rlast,args...)`,
(2) `std::for_each_n(rfirst,args...)`,
(3) `std::copy_n(rfirst,args...)`,
(4) `std::rotate_copy(rfirst,rmiddle,rlast,args...)`,
and `rfirst`, `rmiddle` and `rlast` are iterator-like objects behaving like their `first`, `middle` and `last` counterparts except that they dereference to the corresponding subobject (`const`) `U&` if pointing to a segment for `U` and `U` is in `Us...` [26].
Effects: Equivalent to `expr`.
Returns: `expr`.
Complexity: That of `expr`.
Note: In the case of closed collections, if `Us...` is not empty and contains all the acceptable types of the collection (total restitution), then the dereference operation of `rfirst`, `rmiddle` and `rlast` to the collection's `value_type` is not ever instantiated.

[21] This is a metalinguistic definition not directly expressible in C++. There are equivalent formulations that can indeed be realized in C++, but they add little to the comprehension of the concepts.

[22] The global `end()` iterator lies outside any segment, hence it always remain valid.

[23] Note that, unlike `c.insert(i1,i2)`, these versions do not throw due to type registration problems.

[24] That is, the hint remains stable even if `it` may become invalid due to reallocations.

[25] The two previous notes apply here.

[26] Strictly speaking a proper `ForwardIterator` cannot behave like this as dereferencing must yield exactly a (`const`) `value_type&` value, which disallows this type of polymorphism.