mirror of
https://github.com/nlohmann/json.git
synced 2026-10-03 21:20:30 +00:00
Document GCC < 11 incomplete-type error with optional members (#3669)
With GCC 10 and older in C++11/14 mode, a free to_json() for a type holding an optional<Dummy> (Dummy constructible from json) fails with "invalid use of incomplete type detector<...to_json_function...>". ADL for Dummy finds the unrelated to_json and closes an instantiation cycle through optional's converting constructor. The same error reproduces without the library, so it can't be fixed here. Add a FAQ entry explaining the cause and the hidden-friend workaround, recommend hidden friends in the arbitrary types docs, and add a regression test that keeps the workaround compiling on GCC 7-10. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -241,6 +241,51 @@ class my_allocator : public std::allocator<T>
|
||||
};
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #3669
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
// mimics boost::optional's converting constructor, whose SFINAE check asks
|
||||
// whether T is constructible from const U&
|
||||
template<class T, class Arg>
|
||||
struct issue3669_is_constructible
|
||||
{
|
||||
template<class T2, class A2, class = decltype(T2(std::declval<A2>()))>
|
||||
static char test(int);
|
||||
template<class, class>
|
||||
static long test(...);
|
||||
static constexpr bool value = sizeof(test<T, Arg>(0)) == 1;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class issue3669_optional
|
||||
{
|
||||
public:
|
||||
issue3669_optional() = default;
|
||||
template<class U>
|
||||
issue3669_optional(const issue3669_optional<U>& /*unused*/, // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
typename std::enable_if<issue3669_is_constructible<T, const U&>::value, bool>::type /*unused*/ = true) {}
|
||||
};
|
||||
|
||||
class Issue3669Dummy
|
||||
{
|
||||
public:
|
||||
explicit Issue3669Dummy(const json& /*unused*/) {}
|
||||
};
|
||||
|
||||
class Issue3669Holder
|
||||
{
|
||||
issue3669_optional<Issue3669Dummy> d{};
|
||||
|
||||
// GCC < 11 (C++11/14) rejects a free to_json(json&, const Issue3669Holder&)
|
||||
// here, because ADL for Issue3669Dummy finds it and closes an instantiation
|
||||
// cycle; a hidden friend is only visible to ADL for Issue3669Holder
|
||||
friend void to_json(json& j, const Issue3669Holder& /*unused*/)
|
||||
{
|
||||
j = "holder";
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("regression tests 2")
|
||||
{
|
||||
SECTION("issue #1001 - Fix memory leak during parser callback")
|
||||
@@ -766,6 +811,14 @@ TEST_CASE("regression tests 2")
|
||||
CHECK(j == k);
|
||||
}
|
||||
|
||||
SECTION("issue #3669 - invalid use of incomplete type with optional member and to_json")
|
||||
{
|
||||
const Issue3669Holder h{};
|
||||
const Issue3669Holder h2(h); // NOLINT(performance-unnecessary-copy-initialization)
|
||||
const json j = h2;
|
||||
CHECK(j == "holder");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("regression test - parser callback must not lose a duplicate key's prior value")
|
||||
|
||||
Reference in New Issue
Block a user