This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++14 status.
unordered_map::insert(T&&) protection should apply to map tooSection: 23.4.3.4 [map.modifiers], 23.4.4.3 [multimap.modifiers], 23.5.3.4 [unord.map.modifiers], 23.5.4.3 [unord.multimap.modifiers] Status: C++14 Submitter: P.J. Plauger Opened: 2010-10-14 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [map.modifiers].
View all issues with C++14 status.
Discussion:
In [unord.map.modifiers], the signature:
template <class P>
pair<iterator, bool> insert(P&& obj);
now has an added Remarks paragraph:
Remarks: This signature shall not participate in overload resolution unless
Pis implicitly convertible tovalue_type.
The same is true for unordered_multimap.
map nor multimap have this constraint, even though it is a
Good Thing(TM) in those cases as well.
[ The submitter suggests: Add the same Remarks clause to [map.modifiers] and [multimap.modifiers]. ]
[ 2010-10-29 Daniel comments: ]
I believe both paragraphs need more cleanup: First, the current Requires element conflict with the Remark;
second, it seems to me that the whole single Requires element is intended to be split into a Requires
and an Effects element; third, the reference to tuple is incorrect (noticed by Paolo Carlini);
fourth, it refers to some non-existing InputIterator parameter relevant for a completely different
overload; sixth, the return type of the overload with hint is wrong.
The following proposed resolution tries to solve these issues as well and uses similar wording as for
the corresponding unordered containers. Unfortunately it has some redundancy over Table 99, but I did
not remove the specification because of the more general template parameter P - the Table 99
requirements apply only for an argument identical to value_type.
- Change 23.4.3.4 [map.modifiers] around p. 1 as indicated:
template <class P> pair<iterator, bool> insert(P&& x); template <class P>pair<iterator, bool>insert(const_iterator position, P&& x);1 Requires:
Pshall be convertible tovalue_typeis constructible fromstd::forward<P>(x)..IfPis instantiated as a reference type, then the argumentxis copied from. Otherwisexis considered to be an rvalue as it is converted tovalue_typeand inserted into the map. Specifically, in such casesCopyConstructibleis not required ofkey_typeormapped_typeunless the conversion fromPspecifically requires it (e.g., ifPis atuple<const key_type, mapped_type>, thenkey_typemust beCopyConstructible). The signature takingInputIteratorparameters does not requireCopyConstructibleof eitherkey_typeormapped_typeif the dereferencedInputIteratorreturns a non-const rvaluepair<key_type,mapped_type>. OtherwiseCopyConstructibleis required for bothkey_typeandmapped_type.
? Effects: Insertsxconverted tovalue_typeif and only if there is no element in the container with key equivalent to the key ofvalue_type(x). For the second form, the iteratorpositionis a hint pointing to where the search should start. ? Returns: For the first form, theboolcomponent of the returnedpairobject indicates whether the insertion took place and the iterator component - or for the second form the returned iterator - points to the element with key equivalent to the key ofvalue_type(x). ? Complexity: Logarithmic in general, but amortized constant ifxis inserted right beforeposition. ? Remarks: These signatures shall not participate in overload resolution unlessPis implicitly convertible tovalue_type.- Change 23.4.4.3 [multimap.modifiers] around p. 1 as indicated:
template <class P> iterator insert(P&& x); template <class P> iterator insert(const_iterator position, P&& x);1 Requires:
Pshall be convertible tovalue_typeis constructible fromstd::forward<P>(x).IfPis instantiated as a reference type, then the argumentxis copied from. Otherwisexis considered to be an rvalue as it is converted tovalue_typeand inserted into the map. Specifically, in such casesCopyConstructibleis not required ofkey_typeormapped_typeunless the conversion fromPspecifically requires it (e.g., ifPis atuple<const key_type, mapped_type>, thenkey_typemust beCopyConstructible). The signature takingInputIteratorparameters does not requireCopyConstructibleof eitherkey_typeormapped_typeif the dereferencedInputIteratorreturns a non-const rvaluepair<key_type, mapped_type>. OtherwiseCopyConstructibleis required for bothkey_typeandmapped_type.
? Effects: Insertsxconverted tovalue_type. For the second form, the iteratorpositionis a hint pointing to where the search should start. ? Returns: An iterator that points to the element with key equivalent to the key ofvalue_type(x). ? Complexity: Logarithmic in general, but amortized constant ifxis inserted right beforeposition. ? Remarks: These signatures shall not participate in overload resolution unlessPis implicitly convertible tovalue_type.
[ 2010 Batavia: ]
We need is_convertible, not is_constructible, both in ordered and unordered containers.
[ 2011 Bloomington ]
The effects of these inserts can be concisely stated in terms of emplace(). Also, the correct term is "EmplaceConstructible", not "constructible".
New wording by Pablo, eliminating duplicate requirements already implied by the effects clause. Move to Review.
[ 2011-10-02 Daniel comments and refines the proposed wording ]
Unfortunately the template constraints expressed as "
Pis implicitly convertible tovalue_type" reject the intended effect to support move-only key types, which was the original intention when the library became move-enabled through the rvalue-reference proposals by Howard (This can clearly be deduced from existing carefully selected wording that emphasizes thatCopyConstructibleis only required for special situations involving lvalues or const rvalues as arguments). The root of the problem is based on current core rules, where an "implicitly converted" value has copy-initialization semantics. Consider a move-only key typeKM, some mapped typeT, and a source valuepof typePequal tostd::pair<KM, T>, this is equivalent to:std::pair<const KM, T> dest = std::move(p);Now 9.5 [dcl.init] p16 b6 sb2 says that the effects of this heterogeneous copy-initialization (
But the actual code that is required (with the default allocator) is simply a direct-initialization fromphas a different type thandest) are as-if a temporary of the target typestd::pair<const KM, T>is produced from the rvaluepof typeP(which is fine), and this temporary is used to initializedest. This second step cannot succeed, because we cannot move fromconst KMtoconst KM. This means thatstd::is_convertible<P, std::pair<const KM, T>>::valueis false.Ptovalue_type, so imposing an implicit conversion is more than necessary. Therefore I strongly recommend to reduce the "overload participation" constraint tostd::is_constructible<std::pair<const KM, T>, P>::valueinstead. This change is the only change that has been performed to the previous proposed wording from Pablo shown below.
[2012, Kona]
Moved to Tentatively Ready by the post-Kona issues processing subgroup, after much discussion on Daniel's analysis of Copy Initialization and move semantics, which we ultimately agreed with.
[2012, Portland: applied to WP]
Proposed resolution:
template <class P> pair<iterator, bool> insert(P&& x); template <class P>pair<iterator, bool>insert(const_iterator position, P&& x);1 Requires:Pshall be convertible tovalue_type.IfPis instantiated as a reference type, then the argumentxis copied from. Otherwisexis considered to be an rvalue as it is converted tovalue_typeand inserted into the map. Specifically, in such casesCopyConstructibleis not required ofkey_typeormapped_typeunless the conversion fromPspecifically requires it (e.g., ifPis atuple<const key_type, mapped_type>, thenkey_typemust beCopyConstructible). The signature takingInputIteratorparameters does not requireCopyConstructibleof eitherkey_typeormapped_typeif the dereferencedInputIteratorreturns a non-const rvaluepair<key_type,mapped_type>. OtherwiseCopyConstructibleis required for bothkey_typeandmapped_type.
? Effects: The first form is equivalent toreturn emplace(std::forward<P>(x)). The second form is equivalent toreturn emplace_hint(position, std::forward<P>(x)). ? Remarks: These signatures shall not participate in overload resolution unlessstd::is_constructible<value_type, P&&>::valueis true.
template <class P> iterator insert(P&& x); template <class P> iterator insert(const_iterator position, P&& x);1 Requires:Pshall be convertible tovalue_type.IfPis instantiated as a reference type, then the argumentxis copied from. Otherwisexis considered to be an rvalue as it is converted tovalue_typeand inserted into the map. Specifically, in such casesCopyConstructibleis not required ofkey_typeormapped_typeunless the conversion fromPspecifically requires it (e.g., ifPis atuple<const key_type, mapped_type>, thenkey_typemust beCopyConstructible). The signature takingInputIteratorparameters does not requireCopyConstructibleof eitherkey_typeormapped_typeif the dereferencedInputIteratorreturns a non-const rvaluepair<key_type, mapped_type>. OtherwiseCopyConstructibleis required for bothkey_typeandmapped_type.
? Effects: The first form is equivalent toreturn emplace(std::forward<P>(x)). The second form is equivalent toreturn emplace_hint(position, std::forward<P>(x)). ? Remarks: These signatures shall not participate in overload resolution unlessstd::is_constructible<value_type, P&&>::valueis true.
template <class P> pair<iterator, bool> insert(P&& obj);1 Requires:2 Effects: equivalent tovalue_typeis constructible fromstd::forward<P>(obj).return emplace(std::forward<P>(obj)).Inserts obj converted tovalue_typeif and only if there is no element in the container with key equivalent to the key ofvalue_type(obj).3 Returns: The bool component of the returned pair object indicates whether the insertion took place and the iterator component points to the element with key equivalent to the key ofvalue_type(obj).4 Complexity: Average case O(1), worst case O(size()).53 Remarks: This signature shall not participate in overload resolution unlessPis implicitly convertible tovalue_typestd::is_constructible<value_type, P&&>::valueis true.template <class P> iterator insert(const_iterator hint, P&& obj);6 Requires:value_typeis constructible fromstd::forward<P>(obj).7? Effects: equivalent toreturn emplace_hint(hint, std::forward<P>(obj)).Inserts obj converted tovalue_typeif and only if there is no element in the container with key equivalent to the key ofvalue_type(obj). The iterator hint is a hint pointing to where the search should start.8 Returns: An iterator that points to the element with key equivalent to the key ofvalue_type(obj).9 Complexity: Average case O(1), worst case O(size()).10? Remarks: This signature shall not participate in overload resolution unlessPis implicitly convertible tovalue_typestd::is_constructible<value_type, P&&>::valueis true.
template <class P> iterator insert(P&& obj);1 Requires:2 Effects: equivalent tovalue_typeis constructible fromstd::forward<P>(obj).return emplace(std::forward<P>(obj)).Inserts obj converted tovalue_type.3 Returns: An iterator that points to the element with key equivalent to the key ofvalue_type(obj).4 Complexity: Average case O(1), worst case O(size()).53 Remarks: This signature shall not participate in overload resolution unlessPis implicitly convertible tovalue_typestd::is_constructible<value_type, P&&>::valueis true.template <class P> iterator insert(const_iterator hint, P&& obj);6 Requires:value_typeis constructible fromstd::forward<P>(obj).7? Effects: equivalent toreturn emplace_hint(hint, std::forward<P>(obj)).Inserts obj converted tovalue_type. The iterator hint is a hint pointing to where the search should start.8 Returns: An iterator that points to the element with key equivalent to the key ofvalue_type(obj).9 Complexity: Average case O(1), worst case O(size()).10? Remarks: This signature shall not participate in overload resolution unlessPis implicitly convertible tovalue_typestd::is_constructible<value_type, P&&>::valueis true.