Add JSON_DISABLE_TUPLE_REFERENCE_CONVERSION to fix std::tuple conversions

basic_json can be constructed from std::tuple<json&>, which it turns into
a one-element array. Because of this, std::tuple picks its converting
constructor that converts the whole source tuple instead of the
element-wise one. As a result, std::tuple<const json&> built from
std::forward_as_tuple(j) binds to a temporary (a compile error with libc++,
a dangling reference with other standard libraries), and std::tuple<json>
built the same way holds [j] instead of a copy of j.

The new opt-in macro JSON_DISABLE_TUPLE_REFERENCE_CONVERSION (CMake option
JSON_DisableTupleReferenceConversion) removes the conversion from a
one-element tuple holding a reference to the same basic_json type, so
std::tuple converts element-wise. It is off by default, so existing
behavior is unchanged. It does not change any function body and therefore
is not part of the ABI tag.

Fixes #2226

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann
2026-09-27 17:17:51 +02:00
parent f682cd2ef1
commit c5f1694b01
17 changed files with 296 additions and 3 deletions
+18
View File
@@ -18,6 +18,11 @@
// for some reason including this after the json header leads to linker errors with VS 2017...
#include <locale>
// skip tests if JSON_DISABLE_TUPLE_REFERENCE_CONVERSION=1 (#2226)
#if defined(JSON_DISABLE_TUPLE_REFERENCE_CONVERSION) && (JSON_DISABLE_TUPLE_REFERENCE_CONVERSION == 1)
#define SKIP_TESTS_FOR_TUPLE_REFERENCE_CONVERSION
#endif
#define JSON_TESTS_PRIVATE
#include <nlohmann/json.hpp>
using json = nlohmann::json;
@@ -28,6 +33,7 @@ using ordered_json = nlohmann::ordered_json;
#include <cstdio>
#include <list>
#include <tuple>
#include <type_traits>
#include <utility>
@@ -541,6 +547,18 @@ TEST_CASE("regression tests 2")
)));
}
#ifndef SKIP_TESTS_FOR_TUPLE_REFERENCE_CONVERSION
SECTION("issue #2226 - std::tuple dangling reference - implicit conversion")
{
// by default, a one-element tuple holding a json reference converts to
// a one-element array; JSON_DISABLE_TUPLE_REFERENCE_CONVERSION removes
// this conversion (see unit-disable-tuple-reference-conversion.cpp)
const json j = true;
CHECK(std::is_constructible<json, std::tuple<const json&>>::value);
CHECK(json(std::forward_as_tuple(j)) == json::array({true}));
}
#endif
SECTION("PR #2181 - regression bug with lvalue")
{
// see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060