...one of the most highly
regarded and expertly designed C++ library projects in the
world. — Herb Sutter and Andrei
This is the constraint on the
template parameter to
std::enable_if_t< std::is_class<Derived>::value && std::is_same<Derived, std::remove_cv_t<Derived>>::value>
This prevents instantiating an interface template with an
const type, a reference type,
Further constraints are not possible (for instance, that
view_interface is given a
Derived template parameter for a type that
Derived is an incomplete
type within each *
The interface templates rely mostly on public members provided by their
Derived template parameter. However,
requires you to supply
base_reference() functions if you want it to act like an adaptor.
Since at least the non-
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
There wouldn't be much point in adding this functionality to
view_interface, because it only
Derived type anyway.
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.
iterator_interface 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
When you make a proxy iterator, you typically use the
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
templates have very few template parameters. For
view_interface, this is because
there are no member typedefs in the
it was deemed ridiculous to create a template whose purpose is to reduce code
size, which takes 14 template parameters.
could deduce some of the nested types required for a standard sequence container.
be deduced as
However, a type
D derived from
may need to use some of these nested types — like
— 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
This leaves the user in the awkward position of defining the same nested type
with a different name that can be used within
It seems better to leave these types for the user to define.
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.
It may not be immediately obvious, but
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
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
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.
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.