From b0e5965d712c501d6043eac17437c7a033d54ae3 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Thu, 17 Jun 2021 13:17:43 -0400 Subject: [PATCH] Properly constrain the basic_json conversion operator Fixes #2491 --- include/nlohmann/detail/meta/detected.hpp | 3 +++ include/nlohmann/detail/meta/type_traits.hpp | 3 +++ include/nlohmann/json.hpp | 22 +++++++++-------- single_include/nlohmann/json.hpp | 26 +++++++++++++------- test/src/unit-regression2.cpp | 6 +++++ 5 files changed, 41 insertions(+), 19 deletions(-) diff --git a/include/nlohmann/detail/meta/detected.hpp b/include/nlohmann/detail/meta/detected.hpp index 7b5a00353..8480e1c05 100644 --- a/include/nlohmann/detail/meta/detected.hpp +++ b/include/nlohmann/detail/meta/detected.hpp @@ -39,6 +39,9 @@ struct detector>, Op, Args...> template class Op, class... Args> using is_detected = typename detector::value_t; +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + template class Op, class... Args> using detected_t = typename detector::type; diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 22d0bfe04..163eb01be 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -157,6 +157,9 @@ template struct conjunction : std::conditional, B1>::type {}; +// https://en.cppreference.com/w/cpp/types/negation +template 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. diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 94c004227..cda764262 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -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::value&& - !std::is_same>::value&& - !std::is_same::value&& - !detail::is_basic_json::value - && !std::is_same>::value + detail::conjunction < + detail::negation>, + detail::negation>>, + detail::negation>, + detail::negation>, + detail::negation>>, + #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) - && !std::is_same::value + detail::negation>, #endif - && detail::is_detected::value - , int >::type = 0 > - JSON_EXPLICIT operator ValueType() const + detail::is_detected_lazy + >::value, int >::type = 0 > + JSON_EXPLICIT operator ValueType() const { // delegate the call to get<>() const return get(); @@ -8907,7 +8909,7 @@ template<> inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible::value&& // NOLINT(misc-redundant-expression) is_nothrow_move_assignable::value -) + ) { j1.swap(j2); } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 5bcd9308f..19fa04c86 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -3309,6 +3309,9 @@ struct detector>, Op, Args...> template class Op, class... Args> using is_detected = typename detector::value_t; +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + template class Op, class... Args> using detected_t = typename detector::type; @@ -3554,6 +3557,9 @@ template struct conjunction : std::conditional, B1>::type {}; +// https://en.cppreference.com/w/cpp/types/negation +template 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. @@ -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::value&& - !std::is_same>::value&& - !std::is_same::value&& - !detail::is_basic_json::value - && !std::is_same>::value + detail::conjunction < + detail::negation>, + detail::negation>>, + detail::negation>, + detail::negation>, + detail::negation>>, + #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) - && !std::is_same::value + detail::negation>, #endif - && detail::is_detected::value - , int >::type = 0 > - JSON_EXPLICIT operator ValueType() const + detail::is_detected_lazy + >::value, int >::type = 0 > + JSON_EXPLICIT operator ValueType() const { // delegate the call to get<>() const return get(); diff --git a/test/src/unit-regression2.cpp b/test/src/unit-regression2.cpp index ef9d7ee54..fa5de3179 100644 --- a/test/src/unit-regression2.cpp +++ b/test/src/unit-regression2.cpp @@ -39,6 +39,7 @@ using nlohmann::json; #include #include +#include #include #if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 @@ -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::value, ""); + } }