Skip to content

Commit

Permalink
Fix issue #1237
Browse files Browse the repository at this point in the history
* Make the conversion operator SFINAE correct.
* Workaround a GCC bug with some traits in type_traits.hpp
  • Loading branch information
theodelrieu committed Sep 12, 2018
1 parent 186c747 commit 697dc23
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 10 deletions.
24 changes: 19 additions & 5 deletions include/nlohmann/detail/meta/type_traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ using to_json_function = decltype(T::to_json(std::declval<Args>()...));
template <typename T, typename... Args>
using from_json_function = decltype(T::from_json(std::declval<Args>()...));

template <typename T, typename U>
using get_template_function = decltype(std::declval<T>().template get<U>());

///////////////////
// is_ functions //
///////////////////
Expand Down Expand Up @@ -185,8 +188,12 @@ struct is_compatible_integer_type
CompatibleNumberIntegerType> {};

// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
template<typename BasicJsonType, typename T>
struct has_from_json
template <typename BasicJsonType, typename T, typename = void>
struct has_from_json : std::false_type {};

template <typename BasicJsonType, typename T>
struct has_from_json<BasicJsonType, T,
enable_if_t<not is_basic_json<T>::value>>
{
using serializer = typename BasicJsonType::template json_serializer<T, void>;

Expand All @@ -197,8 +204,11 @@ struct has_from_json

// This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types
template <typename BasicJsonType, typename T, typename = void>
struct has_non_default_from_json : std::false_type {};

template<typename BasicJsonType, typename T>
struct has_non_default_from_json
struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
{
using serializer = typename BasicJsonType::template json_serializer<T, void>;

Expand All @@ -208,8 +218,12 @@ struct has_non_default_from_json
};

// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
template<typename BasicJsonType, typename T>
struct has_to_json
// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
template <typename BasicJsonType, typename T, typename = void>
struct has_to_json : std::false_type {};

template <typename BasicJsonType, typename T>
struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
{
using serializer = typename BasicJsonType::template json_serializer<T, void>;

Expand Down
2 changes: 2 additions & 0 deletions include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2828,12 +2828,14 @@ class basic_json
not std::is_same<ValueType, detail::json_ref<basic_json>>::value and
not std::is_same<ValueType, typename string_t::value_type>::value and
not detail::is_basic_json<ValueType>::value

#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
#if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914
and not std::is_same<ValueType, typename std::string_view>::value
#endif
#endif
and detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value
, int >::type = 0 >
operator ValueType() const
{
Expand Down
26 changes: 21 additions & 5 deletions single_include/nlohmann/json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,9 @@ using to_json_function = decltype(T::to_json(std::declval<Args>()...));
template <typename T, typename... Args>
using from_json_function = decltype(T::from_json(std::declval<Args>()...));

template <typename T, typename U>
using get_template_function = decltype(std::declval<T>().template get<U>());

///////////////////
// is_ functions //
///////////////////
Expand Down Expand Up @@ -545,8 +548,12 @@ struct is_compatible_integer_type
CompatibleNumberIntegerType> {};

// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
template<typename BasicJsonType, typename T>
struct has_from_json
template <typename BasicJsonType, typename T, typename = void>
struct has_from_json : std::false_type {};

template <typename BasicJsonType, typename T>
struct has_from_json<BasicJsonType, T,
enable_if_t<not is_basic_json<T>::value>>
{
using serializer = typename BasicJsonType::template json_serializer<T, void>;

Expand All @@ -557,8 +564,11 @@ struct has_from_json

// This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types
template <typename BasicJsonType, typename T, typename = void>
struct has_non_default_from_json : std::false_type {};

template<typename BasicJsonType, typename T>
struct has_non_default_from_json
struct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
{
using serializer = typename BasicJsonType::template json_serializer<T, void>;

Expand All @@ -568,8 +578,12 @@ struct has_non_default_from_json
};

// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
template<typename BasicJsonType, typename T>
struct has_to_json
// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
template <typename BasicJsonType, typename T, typename = void>
struct has_to_json : std::false_type {};

template <typename BasicJsonType, typename T>
struct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>
{
using serializer = typename BasicJsonType::template json_serializer<T, void>;

Expand Down Expand Up @@ -13901,12 +13915,14 @@ class basic_json
not std::is_same<ValueType, detail::json_ref<basic_json>>::value and
not std::is_same<ValueType, typename string_t::value_type>::value and
not detail::is_basic_json<ValueType>::value

#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
#if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914
and not std::is_same<ValueType, typename std::string_view>::value
#endif
#endif
and detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value
, int >::type = 0 >
operator ValueType() const
{
Expand Down
6 changes: 6 additions & 0 deletions test/src/unit-udt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -811,3 +811,9 @@ TEST_CASE("Issue #924")
CHECK_NOTHROW(j.get<Evil>());
CHECK_NOTHROW(j.get<std::vector<Evil>>());
}

TEST_CASE("Issue #1237")
{
struct non_convertible_type {};
static_assert(not std::is_convertible<json, non_convertible_type>::value, "");
}

0 comments on commit 697dc23

Please sign in to comment.