diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 457f445d..a1def699 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -322,10 +322,10 @@ void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> j = { std::get<Idx>(t)... }; } -template<typename BasicJsonType, typename... Args> -void to_json(BasicJsonType& j, const std::tuple<Args...>& t) +template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0> +void to_json(BasicJsonType& j, const T& t) { - to_json_tuple_impl(j, t, index_sequence_for<Args...> {}); + to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {}); } struct to_json_fn diff --git a/include/nlohmann/detail/meta/type_traits.hpp b/include/nlohmann/detail/meta/type_traits.hpp index 2b2b2d3b..280f6953 100644 --- a/include/nlohmann/detail/meta/type_traits.hpp +++ b/include/nlohmann/detail/meta/type_traits.hpp @@ -357,5 +357,18 @@ struct is_compatible_type_impl < template <typename BasicJsonType, typename CompatibleType> struct is_compatible_type : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; + +// https://en.cppreference.com/w/cpp/types/conjunction +template<class...> struct conjunction : std::true_type { }; +template<class B1> struct conjunction<B1> : B1 { }; +template<class B1, class... Bn> +struct conjunction<B1, Bn...> +: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; + +template <typename T1, typename T2> +struct is_constructible_tuple : std::false_type {}; + +template <typename T1, typename... Args> +struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<std::is_constructible<T1, Args>...> {}; } // namespace detail } // namespace nlohmann diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index b959ec5e..b0ce05fd 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -2794,6 +2794,19 @@ struct is_compatible_type_impl < template <typename BasicJsonType, typename CompatibleType> struct is_compatible_type : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; + +// https://en.cppreference.com/w/cpp/types/conjunction +template<class...> struct conjunction : std::true_type { }; +template<class B1> struct conjunction<B1> : B1 { }; +template<class B1, class... Bn> +struct conjunction<B1, Bn...> +: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; + +template <typename T1, typename T2> +struct is_constructible_tuple : std::false_type {}; + +template <typename T1, typename... Args> +struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<std::is_constructible<T1, Args>...> {}; } // namespace detail } // namespace nlohmann @@ -3753,10 +3766,10 @@ void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> j = { std::get<Idx>(t)... }; } -template<typename BasicJsonType, typename... Args> -void to_json(BasicJsonType& j, const std::tuple<Args...>& t) +template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0> +void to_json(BasicJsonType& j, const T& t) { - to_json_tuple_impl(j, t, index_sequence_for<Args...> {}); + to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {}); } struct to_json_fn diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index d60f7a55..1a60efdc 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1842,6 +1842,12 @@ TEST_CASE("regression tests") static_assert(!std::is_constructible<json, std::pair<NotSerializableData, std::string>>::value, ""); static_assert(std::is_constructible<json, std::pair<int, std::string>>::value, ""); } + SECTION("issue #1825 - A tuple<Args..> is json constructible only if all T in Args are json constructible") + { + static_assert(!std::is_constructible<json, std::tuple<std::string, NotSerializableData>>::value, ""); + static_assert(!std::is_constructible<json, std::tuple<NotSerializableData, std::string>>::value, ""); + static_assert(std::is_constructible<json, std::tuple<int, std::string>>::value, ""); + } } #if not defined(JSON_NOEXCEPTION)