Description
basic_json::emplace(key, value) does not compile for ordered_json when value is an lvalue (or a const lvalue), although the same call compiles for json. It also rejects a single std::pair argument.
basic_json::emplace forwards its arguments to object_t::emplace (include/nlohmann/json.hpp#L4023). std::map::emplace is variadic, but ordered_map only has two overloads whose value parameter is T&& with T being the class template parameter (the mapped type), i.e., an rvalue reference and not a forwarding reference (include/nlohmann/ordered_map.hpp#L73 and #L88):
std::pair<iterator, bool> emplace(const key_type& key, T&& t);
template<class KeyType, ...>
std::pair<iterator, bool> emplace(KeyType && key, T && t);
So only rvalues (including temporaries created by implicit conversion, e.g., oj.emplace("a", 1)) are accepted. The emplace documentation describes template<class... Args> emplace(Args&& ... args) for both json and ordered_json without mentioning this restriction.
Since when: since ordered_json was introduced; v3.9.0 had emplace(key_type&& key, T&& t), and e590604 (v3.9.1) changed the key to const key_type& but kept T&&. The program below fails the same way with the v3.12.0 headers.
Open PR #5609 (head c5d40f0) rewrites how ordered_map::emplace appends, but keeps both signatures; the program below still fails to compile with that PR's ordered_map.hpp.
Possible fix (untested): accept the value by forwarding reference, e.g., template<class V> std::pair<iterator, bool> emplace(const key_type& key, V&& t) constrained on std::is_constructible<T, V&&>, and likewise for the KeyType overload; alternatively add emplace(const key_type&, const T&) overloads. A variadic emplace(Args&&...) like std::map's would also cover the std::pair form, but needs to extract the key before constructing the element.
Reproduction steps
- Save the program below as
c05.cpp.
- Compile it against
develop: clang++ -std=c++17 -I include c05.cpp -o c05 (the same error occurs with -std=c++11 and with GCC 16.2).
Expected vs. actual results
- Expected: the program compiles and prints
{"a":1} {"a":1}.
- Actual: compile error in
basic_json::emplace for the ordered_json call.
Minimal code example
#include <nlohmann/json.hpp>
#include <iostream>
using nlohmann::json;
using nlohmann::ordered_json;
int main()
{
json j = json::object();
json value = 1;
j.emplace("a", value); // compiles
ordered_json oj = ordered_json::object();
ordered_json ovalue = 1;
oj.emplace("a", ovalue); // expected: compiles like the json version
// actual: error: no matching member function for call to 'emplace'
std::cout << j << ' ' << oj << '\n';
}
Error messages
include/nlohmann/json.hpp:4023:43: error: no matching member function for call to 'emplace'
4023 | auto res = m_data.m_value.object->emplace(std::forward<Args>(args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
c05.cpp:15:8: note: in instantiation of function template specialization 'nlohmann::basic_json<nlohmann::ordered_map>::emplace<const char (&)[2], nlohmann::basic_json<nlohmann::ordered_map> &>' requested here
include/nlohmann/ordered_map.hpp:88:31: note: candidate function template not viable: expects an rvalue for 2nd argument
include/nlohmann/ordered_map.hpp:73:31: note: candidate function not viable: expects an rvalue for 2nd argument
1 error generated.
With GCC 16.2:
include/nlohmann/json.hpp:4023:50: error: no matching function for call to 'nlohmann::json_abi_v3_12_0::ordered_map<...>::emplace(const char [2], nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map>&)'
• error: cannot bind rvalue reference of type 'nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map>&&' to lvalue of type 'nlohmann::json_abi_v3_12_0::basic_json<nlohmann::json_abi_v3_12_0::ordered_map>'
Compiler and operating system
Apple clang 21.0.0 (clang-2100.3.34.2), macOS 27.0 (arm64); also GCC 16.2 (/opt/homebrew/bin/g++-16)
Library version
develop @ 633de8e; also 3.12.0
Validation
This issue was written by Claude Code on behalf of @nlohmann.
Description
basic_json::emplace(key, value)does not compile forordered_jsonwhenvalueis an lvalue (or aconstlvalue), although the same call compiles forjson. It also rejects a singlestd::pairargument.basic_json::emplaceforwards its arguments toobject_t::emplace(include/nlohmann/json.hpp#L4023).std::map::emplaceis variadic, butordered_maponly has two overloads whose value parameter isT&&withTbeing the class template parameter (the mapped type), i.e., an rvalue reference and not a forwarding reference (include/nlohmann/ordered_map.hpp#L73and#L88):So only rvalues (including temporaries created by implicit conversion, e.g.,
oj.emplace("a", 1)) are accepted. Theemplacedocumentation describestemplate<class... Args> emplace(Args&& ... args)for bothjsonandordered_jsonwithout mentioning this restriction.Since when: since
ordered_jsonwas introduced; v3.9.0 hademplace(key_type&& key, T&& t), and e590604 (v3.9.1) changed the key toconst key_type&but keptT&&. The program below fails the same way with the v3.12.0 headers.Open PR #5609 (head c5d40f0) rewrites how
ordered_map::emplaceappends, but keeps both signatures; the program below still fails to compile with that PR'sordered_map.hpp.Possible fix (untested): accept the value by forwarding reference, e.g.,
template<class V> std::pair<iterator, bool> emplace(const key_type& key, V&& t)constrained onstd::is_constructible<T, V&&>, and likewise for theKeyTypeoverload; alternatively addemplace(const key_type&, const T&)overloads. A variadicemplace(Args&&...)likestd::map's would also cover thestd::pairform, but needs to extract the key before constructing the element.Reproduction steps
c05.cpp.develop:clang++ -std=c++17 -I include c05.cpp -o c05(the same error occurs with-std=c++11and with GCC 16.2).Expected vs. actual results
{"a":1} {"a":1}.basic_json::emplacefor theordered_jsoncall.Minimal code example
Error messages
With GCC 16.2:
Compiler and operating system
Apple clang 21.0.0 (clang-2100.3.34.2), macOS 27.0 (arm64); also GCC 16.2 (/opt/homebrew/bin/g++-16)
Library version
develop@ 633de8e; also 3.12.0Validation
developbranch is used.This issue was written by Claude Code on behalf of @nlohmann.