Skip to content

Commit 910a895

Browse files
authored
Merge pull request #1238 from theodelrieu/fix/1237
Fix issue #1237
2 parents 22e5534 + 1fae82b commit 910a895

4 files changed

Lines changed: 118 additions & 140 deletions

File tree

include/nlohmann/detail/meta/type_traits.hpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ using to_json_function = decltype(T::to_json(std::declval<Args>()...));
6565
template <typename T, typename... Args>
6666
using from_json_function = decltype(T::from_json(std::declval<Args>()...));
6767

68+
template <typename T, typename U>
69+
using get_template_function = decltype(std::declval<T>().template get<U>());
70+
6871
///////////////////
6972
// is_ functions //
7073
///////////////////
@@ -185,8 +188,12 @@ struct is_compatible_integer_type
185188
CompatibleNumberIntegerType> {};
186189

187190
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
188-
template<typename BasicJsonType, typename T>
189-
struct has_from_json
191+
template <typename BasicJsonType, typename T, typename = void>
192+
struct has_from_json : std::false_type {};
193+
194+
template <typename BasicJsonType, typename T>
195+
struct has_from_json<BasicJsonType, T,
196+
enable_if_t<not is_basic_json<T>::value>>
190197
{
191198
using serializer = typename BasicJsonType::template json_serializer<T, void>;
192199

@@ -197,8 +204,11 @@ struct has_from_json
197204

198205
// This trait checks if JSONSerializer<T>::from_json(json const&) exists
199206
// this overload is used for non-default-constructible user-defined-types
207+
template <typename BasicJsonType, typename T, typename = void>
208+
struct has_non_default_from_json : std::false_type {};
209+
200210
template<typename BasicJsonType, typename T>
201-
struct has_non_default_from_json
211+
struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
202212
{
203213
using serializer = typename BasicJsonType::template json_serializer<T, void>;
204214

@@ -208,8 +218,12 @@ struct has_non_default_from_json
208218
};
209219

210220
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
211-
template<typename BasicJsonType, typename T>
212-
struct has_to_json
221+
// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
222+
template <typename BasicJsonType, typename T, typename = void>
223+
struct has_to_json : std::false_type {};
224+
225+
template <typename BasicJsonType, typename T>
226+
struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
213227
{
214228
using serializer = typename BasicJsonType::template json_serializer<T, void>;
215229

include/nlohmann/json.hpp

Lines changed: 38 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2670,17 +2670,18 @@ class basic_json
26702670

26712671

26722672
/*!
2673-
@brief get a pointer value (explicit)
2673+
@brief get a pointer value (implicit)
26742674
2675-
Explicit pointer access to the internally stored JSON value. No copies are
2675+
Implicit pointer access to the internally stored JSON value. No copies are
26762676
made.
26772677
2678-
@warning The pointer becomes invalid if the underlying JSON object
2679-
changes.
2678+
@warning Writing data to the pointee of the result yields an undefined
2679+
state.
26802680
26812681
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
26822682
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
2683-
@ref number_unsigned_t, or @ref number_float_t.
2683+
@ref number_unsigned_t, or @ref number_float_t. Enforced by a static
2684+
assertion.
26842685
26852686
@return pointer to the internally stored JSON value if the requested
26862687
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@@ -2690,45 +2691,43 @@ class basic_json
26902691
@liveexample{The example below shows how pointers to internal values of a
26912692
JSON value can be requested. Note that no type conversions are made and a
26922693
`nullptr` is returned if the value and the requested pointer type does not
2693-
match.,get__PointerType}
2694-
2695-
@sa @ref get_ptr() for explicit pointer-member access
2694+
match.,get_ptr}
26962695
26972696
@since version 1.0.0
26982697
*/
26992698
template<typename PointerType, typename std::enable_if<
27002699
std::is_pointer<PointerType>::value, int>::type = 0>
2701-
PointerType get() noexcept
2700+
auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
27022701
{
2703-
// delegate the call to get_ptr
2704-
return get_ptr<PointerType>();
2702+
// delegate the call to get_impl_ptr<>()
2703+
return get_impl_ptr(static_cast<PointerType>(nullptr));
27052704
}
27062705

27072706
/*!
2708-
@brief get a pointer value (explicit)
2709-
@copydoc get()
2707+
@brief get a pointer value (implicit)
2708+
@copydoc get_ptr()
27102709
*/
27112710
template<typename PointerType, typename std::enable_if<
2712-
std::is_pointer<PointerType>::value, int>::type = 0>
2713-
constexpr const PointerType get() const noexcept
2711+
std::is_pointer<PointerType>::value and
2712+
std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
2713+
constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
27142714
{
2715-
// delegate the call to get_ptr
2716-
return get_ptr<PointerType>();
2715+
// delegate the call to get_impl_ptr<>() const
2716+
return get_impl_ptr(static_cast<PointerType>(nullptr));
27172717
}
27182718

27192719
/*!
2720-
@brief get a pointer value (implicit)
2720+
@brief get a pointer value (explicit)
27212721
2722-
Implicit pointer access to the internally stored JSON value. No copies are
2722+
Explicit pointer access to the internally stored JSON value. No copies are
27232723
made.
27242724
2725-
@warning Writing data to the pointee of the result yields an undefined
2726-
state.
2725+
@warning The pointer becomes invalid if the underlying JSON object
2726+
changes.
27272727
27282728
@tparam PointerType pointer type; must be a pointer to @ref array_t, @ref
27292729
object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,
2730-
@ref number_unsigned_t, or @ref number_float_t. Enforced by a static
2731-
assertion.
2730+
@ref number_unsigned_t, or @ref number_float_t.
27322731
27332732
@return pointer to the internally stored JSON value if the requested
27342733
pointer type @a PointerType fits to the JSON value; `nullptr` otherwise
@@ -2738,59 +2737,30 @@ class basic_json
27382737
@liveexample{The example below shows how pointers to internal values of a
27392738
JSON value can be requested. Note that no type conversions are made and a
27402739
`nullptr` is returned if the value and the requested pointer type does not
2741-
match.,get_ptr}
2740+
match.,get__PointerType}
2741+
2742+
@sa @ref get_ptr() for explicit pointer-member access
27422743
27432744
@since version 1.0.0
27442745
*/
27452746
template<typename PointerType, typename std::enable_if<
27462747
std::is_pointer<PointerType>::value, int>::type = 0>
2747-
PointerType get_ptr() noexcept
2748-
{
2749-
// get the type of the PointerType (remove pointer and const)
2750-
using pointee_t = typename std::remove_const<typename
2751-
std::remove_pointer<typename
2752-
std::remove_const<PointerType>::type>::type>::type;
2753-
// make sure the type matches the allowed types
2754-
static_assert(
2755-
std::is_same<object_t, pointee_t>::value
2756-
or std::is_same<array_t, pointee_t>::value
2757-
or std::is_same<string_t, pointee_t>::value
2758-
or std::is_same<boolean_t, pointee_t>::value
2759-
or std::is_same<number_integer_t, pointee_t>::value
2760-
or std::is_same<number_unsigned_t, pointee_t>::value
2761-
or std::is_same<number_float_t, pointee_t>::value
2762-
, "incompatible pointer type");
2763-
2764-
// delegate the call to get_impl_ptr<>()
2765-
return get_impl_ptr(static_cast<PointerType>(nullptr));
2748+
auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
2749+
{
2750+
// delegate the call to get_ptr
2751+
return get_ptr<PointerType>();
27662752
}
27672753

27682754
/*!
2769-
@brief get a pointer value (implicit)
2770-
@copydoc get_ptr()
2755+
@brief get a pointer value (explicit)
2756+
@copydoc get()
27712757
*/
27722758
template<typename PointerType, typename std::enable_if<
2773-
std::is_pointer<PointerType>::value and
2774-
std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>
2775-
constexpr const PointerType get_ptr() const noexcept
2776-
{
2777-
// get the type of the PointerType (remove pointer and const)
2778-
using pointee_t = typename std::remove_const<typename
2779-
std::remove_pointer<typename
2780-
std::remove_const<PointerType>::type>::type>::type;
2781-
// make sure the type matches the allowed types
2782-
static_assert(
2783-
std::is_same<object_t, pointee_t>::value
2784-
or std::is_same<array_t, pointee_t>::value
2785-
or std::is_same<string_t, pointee_t>::value
2786-
or std::is_same<boolean_t, pointee_t>::value
2787-
or std::is_same<number_integer_t, pointee_t>::value
2788-
or std::is_same<number_unsigned_t, pointee_t>::value
2789-
or std::is_same<number_float_t, pointee_t>::value
2790-
, "incompatible pointer type");
2791-
2792-
// delegate the call to get_impl_ptr<>() const
2793-
return get_impl_ptr(static_cast<PointerType>(nullptr));
2759+
std::is_pointer<PointerType>::value, int>::type = 0>
2760+
constexpr auto get() const noexcept -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())
2761+
{
2762+
// delegate the call to get_ptr
2763+
return get_ptr<PointerType>();
27942764
}
27952765

27962766
/*!
@@ -2874,12 +2844,14 @@ class basic_json
28742844
not std::is_same<ValueType, detail::json_ref<basic_json>>::value and
28752845
not std::is_same<ValueType, typename string_t::value_type>::value and
28762846
not detail::is_basic_json<ValueType>::value
2847+
28772848
#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
28782849
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
28792850
#if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914
28802851
and not std::is_same<ValueType, typename std::string_view>::value
28812852
#endif
28822853
#endif
2854+
and detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value
28832855
, int >::type = 0 >
28842856
operator ValueType() const
28852857
{

0 commit comments

Comments
 (0)