Merge pull request #919 from theodelrieu/fix/sfinae_for_incomplete_types

fix sfinae on basic_json UDT constructor
This commit is contained in:
Niels Lohmann 2018-01-23 07:32:06 +01:00 committed by GitHub
commit f5c4e9f3a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 20 deletions

View file

@ -96,6 +96,14 @@ template<> struct priority_tag<0> {};
// has_/is_ functions // // has_/is_ functions //
//////////////////////// ////////////////////////
// source: https://stackoverflow.com/a/37193089/4116453
template <typename T, typename = void>
struct is_complete_type : std::false_type {};
template <typename T>
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
NLOHMANN_JSON_HAS_HELPER(mapped_type); NLOHMANN_JSON_HAS_HELPER(mapped_type);
NLOHMANN_JSON_HAS_HELPER(key_type); NLOHMANN_JSON_HAS_HELPER(key_type);
NLOHMANN_JSON_HAS_HELPER(value_type); NLOHMANN_JSON_HAS_HELPER(value_type);
@ -171,7 +179,6 @@ struct is_compatible_integer_type
RealIntegerType, CompatibleNumberIntegerType > ::value; RealIntegerType, CompatibleNumberIntegerType > ::value;
}; };
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_from_json struct has_from_json
@ -221,6 +228,23 @@ struct has_to_json
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
}; };
template <typename BasicJsonType, typename CompatibleCompleteType>
struct is_compatible_complete_type
{
static constexpr bool value =
not std::is_base_of<std::istream, CompatibleCompleteType>::value and
not std::is_same<BasicJsonType, CompatibleCompleteType>::value and
not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
};
template <typename BasicJsonType, typename CompatibleType>
struct is_compatible_type
: conjunction<is_complete_type<CompatibleType>,
is_compatible_complete_type<BasicJsonType, CompatibleType>>
{
};
// taken from ranges-v3 // taken from ranges-v3
template<typename T> template<typename T>
struct static_const struct static_const

View file

@ -1551,15 +1551,13 @@ class basic_json
@since version 2.1.0 @since version 2.1.0
*/ */
template<typename CompatibleType, typename U = detail::uncvref_t<CompatibleType>, template <typename CompatibleType,
detail::enable_if_t<not std::is_base_of<std::istream, U>::value and typename U = detail::uncvref_t<CompatibleType>,
not std::is_same<U, basic_json_t>::value and detail::enable_if_t<
not detail::is_basic_json_nested_type< detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
basic_json_t, U>::value and basic_json(CompatibleType && val) noexcept(noexcept(
detail::has_to_json<basic_json, U>::value, JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
int> = 0> std::forward<CompatibleType>(val))))
basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer<U>::to_json(
std::declval<basic_json_t&>(), std::forward<CompatibleType>(val))))
{ {
JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val)); JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
assert_invariant(); assert_invariant();

View file

@ -310,6 +310,14 @@ template<> struct priority_tag<0> {};
// has_/is_ functions // // has_/is_ functions //
//////////////////////// ////////////////////////
// source: https://stackoverflow.com/a/37193089/4116453
template <typename T, typename = void>
struct is_complete_type : std::false_type {};
template <typename T>
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
NLOHMANN_JSON_HAS_HELPER(mapped_type); NLOHMANN_JSON_HAS_HELPER(mapped_type);
NLOHMANN_JSON_HAS_HELPER(key_type); NLOHMANN_JSON_HAS_HELPER(key_type);
NLOHMANN_JSON_HAS_HELPER(value_type); NLOHMANN_JSON_HAS_HELPER(value_type);
@ -385,7 +393,6 @@ struct is_compatible_integer_type
RealIntegerType, CompatibleNumberIntegerType > ::value; RealIntegerType, CompatibleNumberIntegerType > ::value;
}; };
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_from_json struct has_from_json
@ -435,6 +442,23 @@ struct has_to_json
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value;
}; };
template <typename BasicJsonType, typename CompatibleCompleteType>
struct is_compatible_complete_type
{
static constexpr bool value =
not std::is_base_of<std::istream, CompatibleCompleteType>::value and
not std::is_same<BasicJsonType, CompatibleCompleteType>::value and
not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
};
template <typename BasicJsonType, typename CompatibleType>
struct is_compatible_type
: conjunction<is_complete_type<CompatibleType>,
is_compatible_complete_type<BasicJsonType, CompatibleType>>
{
};
// taken from ranges-v3 // taken from ranges-v3
template<typename T> template<typename T>
struct static_const struct static_const
@ -10379,15 +10403,13 @@ class basic_json
@since version 2.1.0 @since version 2.1.0
*/ */
template<typename CompatibleType, typename U = detail::uncvref_t<CompatibleType>, template <typename CompatibleType,
detail::enable_if_t<not std::is_base_of<std::istream, U>::value and typename U = detail::uncvref_t<CompatibleType>,
not std::is_same<U, basic_json_t>::value and detail::enable_if_t<
not detail::is_basic_json_nested_type< detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
basic_json_t, U>::value and basic_json(CompatibleType && val) noexcept(noexcept(
detail::has_to_json<basic_json, U>::value, JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
int> = 0> std::forward<CompatibleType>(val))))
basic_json(CompatibleType && val) noexcept(noexcept(JSONSerializer<U>::to_json(
std::declval<basic_json_t&>(), std::forward<CompatibleType>(val))))
{ {
JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val)); JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
assert_invariant(); assert_invariant();

View file

@ -692,3 +692,22 @@ TEST_CASE("custom serializer that does adl by default", "[udt]")
CHECK(me == j.get<udt::person>()); CHECK(me == j.get<udt::person>());
CHECK(me == cj.get<udt::person>()); CHECK(me == cj.get<udt::person>());
} }
namespace
{
struct incomplete;
// std::is_constructible is broken on macOS' libc++
// use the cppreference implementation
template <typename T, typename = void>
struct is_constructible_patched : std::false_type {};
template <typename T>
struct is_constructible_patched<T, decltype(void(json(std::declval<T>())))> : std::true_type {};
}
TEST_CASE("an incomplete type does not trigger a compiler error in non-evaluated context", "[udt]")
{
static_assert(not is_constructible_patched<json, incomplete>::value, "");
}