Section: 23.2.7 [associative.reqmts] Status: C++14 Submitter: Daniel Krügler Opened: 2009-09-20 Last modified: 2016-01-28
Priority: Not Prioritized
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with C++14 status.
Discussion:
Scott Meyers' mentions on a recent posting on c.s.c++ some arguments that point to an incomplete resolution of 103 and to an inconsistency of requirements on keys in ordered and unordered associative containers:
1) 103 introduced the term immutable without defining it in a unique manner in 23.2.7 [associative.reqmts]/5:
[..] Keys in an associative container are immutable.
According to conventional dictionaries immutable is an unconditional way of saying that something cannot be changed. So without any further explicit allowance a user always runs into undefined behavior if (s)he attempts to modify such a key. IMO this was not the intend of the committee to resolve 103 in that way because the comments suggest an interpretation that should give any user the freedom to modify the key in an explicit way provided it would not affect the sort order in that container.
2) Another observation was that surprisingly no similar 'safety guards' exists against unintentional key changes for the unordered associative containers, specifically there is no such requirement as in 23.2.7 [associative.reqmts]/6 that "both
iteratorandconst_iteratorare constant iterators". But the need for such protection against unintentional changes as well as the constraints in which manner any explicit changes may be performed are both missing and necessary, because such changes could potentially change the equivalence of keys that is measured by thehasherandkey_equal.I suggest to fix the unconditional wording involved with "immutable keys" by at least adding a hint for the reader that users may perform such changes in an explicit manner and to perform similar wording changes as 103 did for the ordered associative containers also for the unordered containers.
[ 2010-03-27 Daniel provides wording. ]
This update attempts to provide normative wording that harmonizes the key and function object constraints of associative and unordered containers.
[ 2010 Batavia: ]
We're uncomfortable with the first agenda item, and we can live with the second agenda item being applied before or after Madrid.
[ 2011 Bloomington ]
Further discussion persuades us this issue is Ready (and so moved). We may need a further issue clarifying the notion of key value vs. key object, as object identity appears to be important to this wording.
Proposed resolution:
Change 23.2.7 [associative.reqmts]/2 as indicated: [This ensures that associative containers make better clear what this "arbitrary" type is, as the unordered containers do in 23.2.8 [unord.req]/3]
2 Each associative container is parameterized on
Keyand an ordering relationComparethat induces a strict weak ordering (25.4) on elements ofKey. In addition,mapandmultimapassociate an arbitrary mapped typetypeTwith theKey. The object of typeCompareis called the comparison object of a container.
Change 23.2.7 [associative.reqmts]/5 as indicated: [This removes the too strong requirement that keys must not be changed at all and brings this line in sync with 23.2.8 [unord.req]/7. We take care about the real constraints by the remaining suggested changes. The rationale provided by LWG 103 didn't really argue why that addition is necessary, and I believe the remaining additions make it clear that any user changes have strong restrictions]:
5 For
setandmultisetthe value type is the same as the key type. Formapandmultimapit is equal topair<const Key, T>.Keys in an associative container are immutable.
Change 23.2.8 [unord.req]/3+4 as indicated: [The current sentence of p.4 has doesn't say something really new and this whole subclause misses to define the concepts of the container-specific hasher object and predicate object. We introduce the term key equality predicate which is already used in the requirements table. This change does not really correct part of this issue, but is recommended to better clarify the nomenclature and the difference between the function objects and the function object types, which is important, because both can potentially be stateful.]
3 Each unordered associative container is parameterized by
Key, by a function object typeHashthat meets theHashrequirements (20.2.4) and acts as a hash function for argument values of typeKey, and by a binary predicatePredthat induces an equivalence relation on values of typeKey. Additionally,unordered_mapandunordered_multimapassociate an arbitrary mapped typeTwith theKey.4 The container's object of type
Hash- denoted byhash- is called the hash function of the container. The container's object of typePred- denoted bypred- is called the key equality predicate of the container.A hash function is a function object that takes a single argument of type.Keyand returns a value of typestd::size_t
Change 23.2.8 [unord.req]/5 as indicated: [This adds a similar safe-guard as the last sentence of 23.2.7 [associative.reqmts]/3]
5 Two values
k1andk2of typeKeyare considered equivalent if the container's key equality predicatereturnskey_equalfunction objecttruewhen passed those values. Ifk1andk2are equivalent, the container's hash function shall return the same value for both. [Note: thus, when an unordered associative container is instantiated with a non-defaultPredparameter it usually needs a non-defaultHashparameter as well. — end note] For any two keysk1andk2in the same container, callingpred(k1, k2)shall always return the same value. For any keykin a container, callinghash(k)shall always return the same value.
After 23.2.8 [unord.req]/7 add the following new paragraph: [This ensures the same level of compile-time protection that we already require for associative containers. It is necessary for similar reasons, because any change in the stored key which would change it's equality relation to others or would change it's hash value such that it would no longer fall in the same bucket, would break the container invariants]
7 For
unordered_setandunordered_multisetthe value type is the same as the key type. Forunordered_mapandunordered_multimapit isstd::pair<const Key, T>.For unordered containers where the value type is the same as the key type, both
iteratorandconst_iteratorare constant iterators. It is unspecified whether or notiteratorandconst_iteratorare the same type. [Note:iteratorandconst_iteratorhave identical semantics in this case, anditeratoris convertible toconst_iterator. Users can avoid violating the One Definition Rule by always usingconst_iteratorin their function parameter lists. — end note]