[/ / Distributed under the Boost Software License, Version 1.0. (See accompanying / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) /] [section Rationale] [heading There Are Minimal Derived-Type Contraints] This is the constraint on the `Derived` template parameter to _iter_iface_, _view_iface_ and _cont_iface_: std::enable_if_t< std::is_class::value && std::is_same>::value> This prevents instantiating an interface template with an `int`, a `const` type, a reference type, etc. Further constraints are not possible (for instance, that _view_iface_ is given a `Derived` template parameter for a type that has a `begin()` and `end()`), because `Derived` is an incomplete type within each *`_interface` template. [heading Using a Special Access-Granting `struct`] The interface templates rely mostly on public members provided by their `Derived` template parameter. However, _iter_iface_ requires you to supply `base_reference()` functions if you want it to act like an adaptor. Since at least the non-`const` overload provides a non-`const` lvalue reference to one of your types data members, it will break the encapsulation of many types to leave `base_reference()` a public member. To allow users to keep these overloads private, _access_ exists. [heading _iter_iface_ Can Act Like an Adaptor, And the Other Interface Templates Can't] There wouldn't be much point in adding this functionality to _view_iface_, because it only uses the `begin()` and `end()` of the `Derived` type anyway. For _cont_iface_ it also does not make much sense. Consider how many container adaptors you've written. That's a use case that does not come up often. [heading _iter_iface_ Takes a Lot of Template Parameters, And the Other Interface Templates Don't] _iter_iface_ does in fact take a lot of template parameters. However, it usually only takes three: the `Derived` type, the iterator category, and the iterator's `value_type`. When you make a proxy iterator, you typically use the _proxy_iter_iface_ alias, and you again only need the same three template parameters. Though you can opt into more template parameters, the rest are seldom necessary. By contrast, the _view_iface_ and _cont_iface_ templates have very few template parameters. For _view_iface_, this is because there are no member typedefs in the `view` concept. For _cont_iface_, it was deemed ridiculous to create a template whose purpose is to reduce code size, which takes 14 template parameters. [heading _cont_iface_ Does not Deduce Nested Types Like `iterator`] _cont_iface_ could deduce some of the nested types required for a standard sequence container. For instance, `iterator` can be deduced as `decltype(*begin())`. However, a type `D` derived from _cont_iface_ may need to use some of these nested types _emdash_ like `iterator` _emdash_ in its interface or implementation. If this is the case, those nested types are not available early enough in the parse to be used in `D`, if they come from deductions in _cont_iface_. This leaves the user in the awkward position of defining the same nested type with a different name that can be used within `D`. It seems better to leave these types for the user to define. [heading _cont_iface_ Does not Support Associative or Unordered Associative Containers] That's right. Associative containers have an interface that assumes that they are node-based containers. On modern hardware, node-based containers are not very efficient, and I don't want to encourage people to write more of them. Unordered associative containers have an interface that precludes open addressing. I don't want to encourage more of that either. [heading _cont_iface_ Does not Satisfy the Allocator-Aware Container Requirements] It may not be immediately obvious, but _cont_iface_ simply cannot help with the allocator-aware requirements. All of the allocator-aware requirements but 3 are special members and constructors. A _CRTP_ base template is unable to provide those, based on the language rules. That leaves the `allocator_type` typedef, which the user must provide; member `swap()`, which is already a container requirement (the allocator-aware table entry just specifies that member `swap()` must be constant-time); and `get_allocator()`, which again is something the user must provide. Most of the difficulty of dealing with allocators has to do with the implementation details of their use within your container. _cont_iface_ provides missing elements of a sequence container's interface, by calling user-provided members of that same interface. It cannot help you with your container's implementation. [endsect]