Accept lvalues in ordered_map::emplace's value parameter (#5685)

* Accept lvalues in ordered_map::emplace's value parameter

ordered_map::emplace(key, value) took the mapped value only by T&&, an
rvalue reference rather than a forwarding reference, so
ordered_json::emplace("a", value) failed to compile whenever value was
an lvalue or a const lvalue, even though the same call compiles for
json (whose object_t is std::map, with a variadic emplace). Turn the
value parameter into a separately-deduced forwarding reference,
constrained with std::is_constructible so the overloads still only
accept something convertible to the mapped type. std::map-compatible
semantics are unchanged: emplace still does nothing if the key already
exists.

Open PR #5609 also touches ordered_map.hpp (moving values on vector
growth); this change only touches the two emplace() overloads and
should not conflict.

Fixes #5673.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

* Avoid astyle's padding in ordered_map::emplace's template headers

Use detail::conjunction instead of && and drop the redundant V&& in detail::is_constructible, so astyle keeps the usual template formatting. Addresses review comment by @gregmarr.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>

---------

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-10-04 11:46:25 +02:00
committed by GitHub
parent df27cc3d4c
commit 6f2048cd5d
5 changed files with 134 additions and 12 deletions
+9 -6
View File
@@ -74,7 +74,9 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return *this;
}
std::pair<iterator, bool> emplace(const key_type& key, T&& t)
template<class V, detail::enable_if_t<
detail::is_constructible<T, V>::value, int> = 0>
std::pair<iterator, bool> emplace(const key_type& key, V && t)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
@@ -83,13 +85,14 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return {it, false};
}
}
append(key, std::forward<T>(t));
append(key, std::forward<V>(t));
return {std::prev(this->end()), true};
}
template<class KeyType, detail::enable_if_t<
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
std::pair<iterator, bool> emplace(KeyType && key, T && t)
template<class KeyType, class V, detail::enable_if_t<
detail::conjunction<detail::is_usable_as_key_type<key_compare, key_type, KeyType>,
detail::is_constructible<T, V>>::value, int> = 0>
std::pair<iterator, bool> emplace(KeyType && key, V && t)
{
for (auto it = this->begin(); it != this->end(); ++it)
{
@@ -98,7 +101,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return {it, false};
}
}
append(std::forward<KeyType>(key), std::forward<T>(t));
append(std::forward<KeyType>(key), std::forward<V>(t));
return {std::prev(this->end()), true};
}