This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.
try_emplace and insert_or_assign misspecifiedSection: 23.4.3.4 [map.modifiers], 23.5.3.4 [unord.map.modifiers] Status: C++17 Submitter: Thomas Koeppe Opened: 2014-12-17 Last modified: 2017-07-30
Priority: 2
View all other issues in [map.modifiers].
View all issues with C++17 status.
Discussion:
The specification of the try_emplace and insert_or_assign member functions in N4279
contains the following errors and omissions:
In insert_or_assign, each occurrence of std::forward<Args>(args)...
should be std::forward<M>(obj); this is was a mistake introduced in editing.
In try_emplace, the construction of the value_type is misspecified, which
is a mistake that was introduced during the evolution from a one-parameter to a variadic form.
As written, value_type(k, std::forward<Args>(args)...) does not do the right thing;
it can only be used with a single argument, which moreover must be convertible to a mapped_type.
The intention is to allow direct-initialization from an argument pack, and the correct constructor
should be value_type(piecewise_construct, forward_as_tuple(k),
forward_as_tuple(std::forward<Args>(args)...).
Both try_emplace and insert_or_assign are missing requirements on the
argument types. Since the semantics of these functions are specified independent of other functions,
they need to include their requirements.
[2015-02, Cologne]
This issue is related to 2469(i).
AM: The repeated references to "first and third forms" and "second and fourth forms" is a bit cumbersome. Maybe split the four functions?[2015-03-26, Thomas provides improved wording]
The approach is to split the descriptions of the various blocks of four functions into two blocks each so as to make the wording easier to follow.
Previous resolution [SUPERSEDED]:This wording is relative to N4296.
Apply the following changes to section 23.4.3.4 [map.modifiers] p3:
template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires: For the first and third forms,
-3- Effects:value_typeshall beEmplaceConstructibleinto map frompiecewise_construct,forward_as_tuple(k),forward_as_tuple(forward<Args>(args)...). For the second and fourth forms,value_typeshall beEmplaceConstructibleinto map frompiecewise_construct,forward_as_tuple(move(k)),forward_as_tuple(forward<Args>(args)...).If the keyIf the map does already contain an element whose key is equivalent tokalready exists in the map, there is no effect. Otherwise, inserts an element into the map. In the first and third forms, the element is constructed from the arguments asvalue_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments asvalue_type(std::move(k), std::forward<Args>(args)...). In the first two overloads, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent tokk, there is no effect. Otherwise for the first and third forms inserts avalue_typeobjecttconstructed withpiecewise_construct,forward_as_tuple(k),forward_as_tuple(forward<Args>(args)...), for the second and fourth forms inserts avalue_typeobjecttconstructed withpiecewise_construct,forward_as_tuple(move(k)),forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first two overloads, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok.Apply the following changes to section 23.4.3.4 [map.modifiers] p5:
template <class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires:
-5- Effects:is_assignable<mapped_type&, M&&>::valueshall be true. For the first and third forms,value_typeshall beEmplaceConstructibleinto map fromk,forward<M>(obj). For the second and fourth forms,value_typeshall beEmplaceConstructibleinto map frommove(k), forward<M>(obj).If the keyIf the map does already contain an element whose key is equivalent tokdoes not exist in the map, inserts an element into the map. In the first and third forms, the element is constructed from the arguments asvalue_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments asvalue_type(std::move(k), std::forward<Args>(args)...). If the key already exists,std::forward<M>(obj)is assigned to themapped_typecorresponding to the key. In the first two overloads, theboolcomponent of the returned value is true if and only if the insertion took place. The returned iterator points to the element that was inserted or updatedk,forward<M>(obj)is assigned to themapped_typecorresponding to the key. Otherwise the first and third forms inserts avalue_typeobjecttconstructed withk,forward<M>(obj), the second and fourth forms inserts avalue_typeobjecttconstructed withmove(k), forward<M>(obj). -?- Returns: In the first two overloads, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent tok.Apply the following changes to section 23.5.3.4 [unord.map.modifiers] p5:
template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args); template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires: For the first and third forms,
-5- Effects:value_typeshall beEmplaceConstructibleinto unordered_map frompiecewise_construct,forward_as_tuple(k),forward_as_tuple(forward<Args>(args)...). For the second and fourth forms,value_typeshall beEmplaceConstructibleinto unordered_map frompiecewise_construct,forward_as_tuple(move(k)),forward_as_tuple(forward<Args>(args)...).If the keyIf the unordered_map does already contain an element whose key is equivalent tokalready exists in the map, there is no effect. Otherwise, inserts an element into the map. In the first and third forms, the element is constructed from the arguments asvalue_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments asvalue_type(std::move(k), std::forward<Args>(args)...). In the first two overloads, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent tokk, there is no effect. Otherwise for the first and third forms inserts avalue_typeobjecttconstructed withpiecewise_construct,forward_as_tuple(k),forward_as_tuple(forward<Args>(args)...), for the second and fourth forms inserts avalue_typeobjecttconstructed withpiecewise_construct,forward_as_tuple(move(k)),forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first two overloads, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the element of the unordered_map whose key is equivalent tok.Apply the following changes to section 23.5.3.4 [unord.map.modifiers] p7:
template <class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj); template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires:
-7- Effects:is_assignable<mapped_type&, M&&>::valueshall be true. For the first and third forms,value_typeshall beEmplaceConstructibleinto unordered_map fromk,forward<M>(obj). For the second and fourth forms,value_typeshall beEmplaceConstructibleinto unordered_map frommove(k), forward<M>(obj).If the keyIf the unordered_map does already contain an element whose key is equivalent tokdoes not exist in the map, inserts an element into the map. In the first and third forms, the element is constructed from the arguments asvalue_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments asvalue_type(std::move(k), std::forward<Args>(args)...). If the key already exists,std::forward<M>(obj)is assigned to themapped_typecorresponding to the key. In the first two overloads, theboolcomponent of the returned value is true if and only if the insertion took place. The returned iterator points to the element that was inserted or updatedk,forward<M>(obj)is assigned to themapped_typecorresponding to the key. Otherwise the first and third forms inserts avalue_typeobjecttconstructed withk,forward<M>(obj), the second and fourth forms inserts avalue_typeobjecttconstructed withmove(k), forward<M>(obj). -?- Returns: In the first two overloads, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the element of the unordered_map whose key is equivalent tok.
[2015-05, Lenexa]
STL: existing wording is horrible, this is Thomas' wording and his issue
STL: already implemented the piecewise part
MC: ok with changes
STL: changes are mechanical
STL: believe this is P1, it must be fixed, we have wording
PJP: functions are sensible
STL: has been implemented
MC: consensus is to move to ready
Proposed resolution:
This wording is relative to N4296.
Apply the following changes to 23.4.3.4 [map.modifiers] p3+p4:
template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires:
-3- Effects:value_typeshall beEmplaceConstructibleintomapfrompiecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...).If the keyIf the map already contains an element whose key is equivalent tokalready exists in the map, there is no effect. Otherwise, inserts an element into the map. In the first and third forms, the element is constructed from the arguments asvalue_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments asvalue_type(std::move(k), std::forward<Args>(args)...). In the first two overloads, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent tokk, there is no effect. Otherwise inserts an object of typevalue_typeconstructed withpiecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first overload, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok. -4- Complexity: The same asemplaceandemplace_hint, respectively.template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires:
-?- Effects: If the map already contains an element whose key is equivalent tovalue_typeshall beEmplaceConstructibleintomapfrompiecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...).k, there is no effect. Otherwise inserts an object of typevalue_typeconstructed withpiecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first overload, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok. -?- Complexity: The same asemplaceandemplace_hint, respectively.
Apply the following changes to 23.4.3.4 [map.modifiers] p5+p6:
template <class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires:
-5- Effects:is_assignable<mapped_type&, M&&>::valueshall betrue.value_typeshall beEmplaceConstructibleintomapfromk, forward<M>(obj).If the keyIf the map already contains an elementkdoes not exist in the map, inserts an element into the map. In the first and third forms, the element is constructed from the arguments asvalue_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments asvalue_type(std::move(k), std::forward<Args>(args)...). If the key already exists,std::forward<M>(obj)is assigned to themapped_typecorresponding to the key. In the first two overloads, theboolcomponent of the returned value is true if and only if the insertion took place. The returned iterator points to the element that was inserted or updatedewhose key is equivalent tok, assignsforward<M>(obj)toe.second. Otherwise inserts an object of typevalue_typeconstructed withk, forward<M>(obj). -?- Returns: In the first overload, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok. -6- Complexity: The same asemplaceandemplace_hint, respectively.template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires:
-?- Effects: If the map already contains an elementis_assignable<mapped_type&, M&&>::valueshall betrue.value_typeshall beEmplaceConstructibleintomapfrommove(k), forward<M>(obj).ewhose key is equivalent tok, assignsforward<M>(obj)toe.second. Otherwise inserts an object of typevalue_typeconstructed withmove(k), forward<M>(obj). -?- Returns: In the first overload, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok. -?- Complexity: The same asemplaceandemplace_hint, respectively.
Apply the following changes to 23.5.3.4 [unord.map.modifiers] p5+p6:
template <class... Args> pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);template <class... Args> iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires:
-5- Effects:value_typeshall beEmplaceConstructibleintounordered_mapfrompiecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...).If the keyIf the map already contains an element whose key is equivalent tokalready exists in the map, there is no effect. Otherwise, inserts an element into the map. In the first and third forms, the element is constructed from the arguments asvalue_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments asvalue_type(std::move(k), std::forward<Args>(args)...). In the first two overloads, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent tokk, there is no effect. Otherwise inserts an object of typevalue_typeconstructed withpiecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first overload, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok. -6- Complexity: The same asemplaceandemplace_hint, respectively.template <class... Args> pair<iterator, bool> try_emplace(key_type&& k, Args&&... args); template <class... Args> iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);-?- Requires:
-?- Effects: If the map already contains an element whose key is equivalent tovalue_typeshall beEmplaceConstructibleintounordered_mapfrompiecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...).k, there is no effect. Otherwise inserts an object of typevalue_typeconstructed withpiecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...). -?- Returns: In the first overload, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok. -?- Complexity: The same asemplaceandemplace_hint, respectively.
Apply the following changes to 23.5.3.4 [unord.map.modifiers] p7+p8:
template <class M> pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);template <class M> iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires:
-7- Effects:is_assignable<mapped_type&, M&&>::valueshall betrue.value_typeshall beEmplaceConstructibleintounordered_mapfromk, forward<M>(obj).If the keyIf the map already contains an elementkdoes not exist in the map, inserts an element into the map. In the first and third forms, the element is constructed from the arguments asvalue_type(k, std::forward<Args>(args)...). In the second and fourth forms, the element is constructed from the arguments asvalue_type(std::move(k), std::forward<Args>(args)...). If the key already exists,std::forward<M>(obj)is assigned to themapped_typecorresponding to the key. In the first two overloads, theboolcomponent of the returned value is true if and only if the insertion took place. The returned iterator points to the element that was inserted or updatedewhose key is equivalent tok, assignsforward<M>(obj)toe.second. Otherwise inserts an object of typevalue_typeconstructed withk, forward<M>(obj). -?- Returns: In the first overload, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok. -8- Complexity: The same asemplaceandemplace_hint, respectively.template <class M> pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj); template <class M> iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);-?- Requires:
-?- Effects: If the map already contains an elementis_assignable<mapped_type&, M&&>::valueshall betrue.value_typeshall beEmplaceConstructibleintounordered_mapfrommove(k), forward<M>(obj).ewhose key is equivalent tok, assignsforward<M>(obj)toe.second. Otherwise inserts an object of typevalue_typeconstructed withmove(k), forward<M>(obj). -?- Returns: In the first overload, theboolcomponent of the returned pair istrueif and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok. -?- Complexity: The same asemplaceandemplace_hint, respectively.