2215. (unordered) associative container functors should be CopyConstructible

Section: 26.2.6 [associative.reqmts], 26.2.7 [unord.req] Status: Open Submitter: Alisdair Meredith Opened: 2012-11-14 Last modified: 2015-10-22

Priority: 3

View other active issues in [associative.reqmts].

View all other issues in [associative.reqmts].

View all issues with Open status.

Discussion:

The requirements on the functors used to arrange elements in the various associative and unordered containers are given by a set of expressions in tables 102 — Associative container requirements, and 103 — Unordered associative container requirements. In keeping with Library convention these expressions make the minimal requirements necessary on their types. For example, we have the following 3 row extracts for the unordered containers:

Expression Assertion/note pre-/post-condition
X(n, hf, eq)
X a(n, hf, eq)
Requires: hasher and key_equal are CopyConstructible.
X(n, hf)
X a(n, hf)
Requires: hasher is CopyConstructible and key_equal is DefaultConstructible.
X(n)
X a(n)
Requires: hasher and key_equal are DefaultConstructible.

However, the signature for each class template requires that the functors must effectively be CopyConstructible for each of these expressions:

template <class Key,
          class T,
          class Hash  = hash<Key>,
          class Pred  = std::equal_to<Key>,
          class Allocator = std::allocator<std::pair<const Key, T> > >
class unordered_map
{
  ...

  // construct/destroy/copy
  explicit unordered_map(size_type n = see below,
                         const hasher& hf = hasher(),
                         const key_equal& eql = key_equal(),
                         const allocator_type& a = allocator_type());

  ...
}

The letter of the standard can be honored as long as implementors recognize their freedom to split this one signature into multiple overloads, so that the documented default arguments (requiring a CopyConstructible functor) are not actually passed as default arguments.

As we look into the requirements for the copy constructor and copy-assignment operator, the requirements are even more vague, as the explicit requirements on the functors are not called out, other than saying that the functors are copied.

Must the functors be CopyAssignable? Or is CopyConstructible sufficient in this case? Do we require that the functors be Swappable so that the copy-swap idiom can be deployed here? Note that a type that is both CopyConstructible and CopyAssignable is still not guaranteed to be Swappable as the user may delete the swap function for their type in their own namespace, which would be found via ADL.

Some clean-up of the requirements table looks necessary, to at least document the assignment behavior. In addition, we should have clear guidance on whether these functors should always be CopyConstructible, as suggested by the class template definitions, or if the requirement tables are correct and we should explicitly split up the constructors in the (unordered) associative containers to no longer use default (function) arguments to obtain their defaulted functors.

I recommend the simplest solution would be to always require that the functors for (unordered) associative containers be CopyConstructible, above the requirements tables themselves, so that the issue need not be addressed within the tables. I suggest that the assignment operators for these containers add the requirement that the functors be Swappable, rather than forwarding the corresponding Assignable requirement.

[2013-03-15 Issues Teleconference]

Moved to Open.

Alisdair to propose wording.

[2014-06-08, Daniel comments]

The area of this issue partially overlaps what LWG 2227 addresses.

[2015-10-20, Daniel comments]

The revised resolution of LWG 2227 should resolve this issue as well. It follows the recommendations of the submitter to require CopyConstructible requirements for the function objects owned by containers, but it does not impose any further fundamental requirements.

Proposed resolution:

See the resolution of LWG 2227.