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.
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_type
shall beEmplaceConstructible
into map frompiecewise_construct
,forward_as_tuple(k)
,forward_as_tuple(forward<Args>(args)...)
. For the second and fourth forms,value_type
shall beEmplaceConstructible
into 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 tok
already 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, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent tok
k
, there is no effect. Otherwise for the first and third forms inserts avalue_type
objectt
constructed withpiecewise_construct
,forward_as_tuple(k)
,forward_as_tuple(forward<Args>(args)...)
, for the second and fourth forms inserts avalue_type
objectt
constructed withpiecewise_construct
,forward_as_tuple(move(k))
,forward_as_tuple(forward<Args>(args)...)
. -?- Returns: In the first two overloads, thebool
component of the returned pair istrue
if 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&&>::value
shall be true. For the first and third forms,value_type
shall beEmplaceConstructible
into map fromk
,forward<M>(obj)
. For the second and fourth forms,value_type
shall beEmplaceConstructible
into map frommove(k), forward<M>(obj)
.If the keyIf the map does already contain an element whose key is equivalent tok
does 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_type
corresponding to the key. In the first two overloads, thebool
component 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_type
corresponding to the key. Otherwise the first and third forms inserts avalue_type
objectt
constructed withk
,forward<M>(obj)
, the second and fourth forms inserts avalue_type
objectt
constructed withmove(k), forward<M>(obj)
. -?- Returns: In the first two overloads, thebool
component of the returned pair istrue
if 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_type
shall beEmplaceConstructible
into unordered_map frompiecewise_construct
,forward_as_tuple(k)
,forward_as_tuple(forward<Args>(args)...)
. For the second and fourth forms,value_type
shall beEmplaceConstructible
into 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 tok
already 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, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent tok
k
, there is no effect. Otherwise for the first and third forms inserts avalue_type
objectt
constructed withpiecewise_construct
,forward_as_tuple(k)
,forward_as_tuple(forward<Args>(args)...)
, for the second and fourth forms inserts avalue_type
objectt
constructed withpiecewise_construct
,forward_as_tuple(move(k))
,forward_as_tuple(forward<Args>(args)...)
. -?- Returns: In the first two overloads, thebool
component of the returned pair istrue
if 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&&>::value
shall be true. For the first and third forms,value_type
shall beEmplaceConstructible
into unordered_map fromk
,forward<M>(obj)
. For the second and fourth forms,value_type
shall beEmplaceConstructible
into unordered_map frommove(k), forward<M>(obj)
.If the keyIf the unordered_map does already contain an element whose key is equivalent tok
does 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_type
corresponding to the key. In the first two overloads, thebool
component 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_type
corresponding to the key. Otherwise the first and third forms inserts avalue_type
objectt
constructed withk
,forward<M>(obj)
, the second and fourth forms inserts avalue_type
objectt
constructed withmove(k), forward<M>(obj)
. -?- Returns: In the first two overloads, thebool
component of the returned pair istrue
if 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_type
shall beEmplaceConstructible
intomap
frompiecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...)
.If the keyIf the map already contains an element whose key is equivalent tok
already 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, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent tok
k
, there is no effect. Otherwise inserts an object of typevalue_type
constructed withpiecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...)
. -?- Returns: In the first overload, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok
. -4- Complexity: The same asemplace
andemplace_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_type
shall beEmplaceConstructible
intomap
frompiecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...)
.k
, there is no effect. Otherwise inserts an object of typevalue_type
constructed withpiecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...)
. -?- Returns: In the first overload, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok
. -?- Complexity: The same asemplace
andemplace_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&&>::value
shall betrue
.value_type
shall beEmplaceConstructible
intomap
fromk, forward<M>(obj)
.If the keyIf the map already contains an elementk
does 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_type
corresponding to the key. In the first two overloads, thebool
component 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 updatede
whose key is equivalent tok
, assignsforward<M>(obj)
toe.second
. Otherwise inserts an object of typevalue_type
constructed withk, forward<M>(obj)
. -?- Returns: In the first overload, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok
. -6- Complexity: The same asemplace
andemplace_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&&>::value
shall betrue
.value_type
shall beEmplaceConstructible
intomap
frommove(k), forward<M>(obj)
.e
whose key is equivalent tok
, assignsforward<M>(obj)
toe.second
. Otherwise inserts an object of typevalue_type
constructed withmove(k), forward<M>(obj)
. -?- Returns: In the first overload, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok
. -?- Complexity: The same asemplace
andemplace_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_type
shall beEmplaceConstructible
intounordered_map
frompiecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...)
.If the keyIf the map already contains an element whose key is equivalent tok
already 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, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent tok
k
, there is no effect. Otherwise inserts an object of typevalue_type
constructed withpiecewise_construct, forward_as_tuple(k), forward_as_tuple(forward<Args>(args)...)
. -?- Returns: In the first overload, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok
. -6- Complexity: The same asemplace
andemplace_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_type
shall beEmplaceConstructible
intounordered_map
frompiecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...)
.k
, there is no effect. Otherwise inserts an object of typevalue_type
constructed withpiecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward<Args>(args)...)
. -?- Returns: In the first overload, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok
. -?- Complexity: The same asemplace
andemplace_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&&>::value
shall betrue
.value_type
shall beEmplaceConstructible
intounordered_map
fromk, forward<M>(obj)
.If the keyIf the map already contains an elementk
does 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_type
corresponding to the key. In the first two overloads, thebool
component 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 updatede
whose key is equivalent tok
, assignsforward<M>(obj)
toe.second
. Otherwise inserts an object of typevalue_type
constructed withk, forward<M>(obj)
. -?- Returns: In the first overload, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok
. -8- Complexity: The same asemplace
andemplace_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&&>::value
shall betrue
.value_type
shall beEmplaceConstructible
intounordered_map
frommove(k), forward<M>(obj)
.e
whose key is equivalent tok
, assignsforward<M>(obj)
toe.second
. Otherwise inserts an object of typevalue_type
constructed withmove(k), forward<M>(obj)
. -?- Returns: In the first overload, thebool
component of the returned pair istrue
if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent tok
. -?- Complexity: The same asemplace
andemplace_hint
, respectively.