Skip to content

Commit

Permalink
Merge pull request #2825 from ldionne/ldionne-lazy
Browse files Browse the repository at this point in the history
Properly constrain the basic_json conversion operator
  • Loading branch information
nlohmann authored Jul 22, 2021
2 parents 19a5e12 + b0e5965 commit a563338
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 19 deletions.
3 changes: 3 additions & 0 deletions include/nlohmann/detail/meta/detected.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ struct detector<Default, void_t<Op<Args...>>, Op, Args...>
template<template<class...> class Op, class... Args>
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;

template<template<class...> class Op, class... Args>
struct is_detected_lazy : is_detected<Op, Args...> { };

template<template<class...> class Op, class... Args>
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;

Expand Down
3 changes: 3 additions & 0 deletions include/nlohmann/detail/meta/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ template<class B1, class... Bn>
struct conjunction<B1, Bn...>
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};

// https://en.cppreference.com/w/cpp/types/negation
template<class B> struct negation : std::integral_constant < bool, !B::value > { };

// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
Expand Down
22 changes: 12 additions & 10 deletions include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3359,17 +3359,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
template < typename ValueType, typename std::enable_if <
!std::is_pointer<ValueType>::value&&
!std::is_same<ValueType, detail::json_ref<basic_json>>::value&&
!std::is_same<ValueType, typename string_t::value_type>::value&&
!detail::is_basic_json<ValueType>::value
&& !std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
detail::conjunction <
detail::negation<std::is_pointer<ValueType>>,
detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,
detail::negation<std::is_same<ValueType, typename string_t::value_type>>,
detail::negation<detail::is_basic_json<ValueType>>,
detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,

#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
&& !std::is_same<ValueType, typename std::string_view>::value
detail::negation<std::is_same<ValueType, std::string_view>>,
#endif
&& detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value
, int >::type = 0 >
JSON_EXPLICIT operator ValueType() const
detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>
>::value, int >::type = 0 >
JSON_EXPLICIT operator ValueType() const
{
// delegate the call to get<>() const
return get<ValueType>();
Expand Down Expand Up @@ -8907,7 +8909,7 @@ template<>
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name)
is_nothrow_move_constructible<nlohmann::json>::value&& // NOLINT(misc-redundant-expression)
is_nothrow_move_assignable<nlohmann::json>::value
)
)
{
j1.swap(j2);
}
Expand Down
26 changes: 17 additions & 9 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3309,6 +3309,9 @@ struct detector<Default, void_t<Op<Args...>>, Op, Args...>
template<template<class...> class Op, class... Args>
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;

template<template<class...> class Op, class... Args>
struct is_detected_lazy : is_detected<Op, Args...> { };

template<template<class...> class Op, class... Args>
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;

Expand Down Expand Up @@ -3554,6 +3557,9 @@ template<class B1, class... Bn>
struct conjunction<B1, Bn...>
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};

// https://en.cppreference.com/w/cpp/types/negation
template<class B> struct negation : std::integral_constant < bool, !B::value > { };

// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
Expand Down Expand Up @@ -20422,17 +20428,19 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
@since version 1.0.0
*/
template < typename ValueType, typename std::enable_if <
!std::is_pointer<ValueType>::value&&
!std::is_same<ValueType, detail::json_ref<basic_json>>::value&&
!std::is_same<ValueType, typename string_t::value_type>::value&&
!detail::is_basic_json<ValueType>::value
&& !std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
detail::conjunction <
detail::negation<std::is_pointer<ValueType>>,
detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,
detail::negation<std::is_same<ValueType, typename string_t::value_type>>,
detail::negation<detail::is_basic_json<ValueType>>,
detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,

#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
&& !std::is_same<ValueType, typename std::string_view>::value
detail::negation<std::is_same<ValueType, std::string_view>>,
#endif
&& detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value
, int >::type = 0 >
JSON_EXPLICIT operator ValueType() const
detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>
>::value, int >::type = 0 >
JSON_EXPLICIT operator ValueType() const
{
// delegate the call to get<>() const
return get<ValueType>();
Expand Down
6 changes: 6 additions & 0 deletions test/src/unit-regression2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ using nlohmann::json;

#include <list>
#include <cstdio>
#include <type_traits>
#include <utility>

#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
Expand Down Expand Up @@ -620,4 +621,9 @@ TEST_CASE("regression tests 2")
nlohmann::to_json(o["foo"], s);
}
}

SECTION("issue #2825 - Properly constrain the basic_json conversion operator")
{
static_assert(std::is_copy_assignable<nlohmann::ordered_json>::value, "");
}
}

0 comments on commit a563338

Please sign in to comment.