Merge pull request #1228 from theodelrieu/remove_static_asserts

Remove static asserts
This commit is contained in:
Niels Lohmann 2018-09-09 18:12:43 +02:00 committed by GitHub
commit d3428b35c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 476 additions and 537 deletions

View file

@ -20,8 +20,10 @@ struct adl_serializer
@param[in,out] val value to write to @param[in,out] val value to write to
*/ */
template<typename BasicJsonType, typename ValueType> template<typename BasicJsonType, typename ValueType>
static void from_json(BasicJsonType&& j, ValueType& val) noexcept( static auto from_json(BasicJsonType&& j, ValueType& val) noexcept(
noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) -> decltype(
::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void()
)
{ {
::nlohmann::from_json(std::forward<BasicJsonType>(j), val); ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
} }
@ -35,9 +37,11 @@ struct adl_serializer
@param[in,out] j JSON value to write to @param[in,out] j JSON value to write to
@param[in] val value to read from @param[in] val value to read from
*/ */
template<typename BasicJsonType, typename ValueType> template <typename BasicJsonType, typename ValueType>
static void to_json(BasicJsonType& j, ValueType&& val) noexcept( static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(
noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val)))) noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))
-> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)),
void())
{ {
::nlohmann::to_json(j, std::forward<ValueType>(val)); ::nlohmann::to_json(j, std::forward<ValueType>(val));
} }

View file

@ -127,16 +127,6 @@ void from_json(const BasicJsonType& j, EnumType& e)
e = static_cast<EnumType>(val); e = static_cast<EnumType>(val);
} }
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
{
if (JSON_UNLIKELY(not j.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
}
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
}
// forward_list doesn't have an insert method // forward_list doesn't have an insert method
template<typename BasicJsonType, typename T, typename Allocator, template<typename BasicJsonType, typename T, typename Allocator,
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
@ -166,24 +156,28 @@ void from_json(const BasicJsonType& j, std::valarray<T>& l)
std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l));
} }
template<typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType>
void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
{ {
using std::end; arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
}
std::transform(j.begin(), j.end(), template <typename BasicJsonType, typename T, std::size_t N>
std::inserter(arr, end(arr)), [](const BasicJsonType & i) auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
priority_tag<2> /*unused*/)
-> decltype(j.template get<T>(), void())
{
for (std::size_t i = 0; i < N; ++i)
{ {
// get<BasicJsonType>() returns *this, this won't call a from_json arr[i] = j.at(i).template get<T>();
// method when value_type is BasicJsonType }
return i.template get<typename CompatibleArrayType::value_type>();
});
} }
template<typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/)
-> decltype( -> decltype(
arr.reserve(std::declval<typename CompatibleArrayType::size_type>()), arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
j.template get<typename CompatibleArrayType::value_type>(),
void()) void())
{ {
using std::end; using std::end;
@ -198,25 +192,34 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio
}); });
} }
template<typename BasicJsonType, typename T, std::size_t N> template <typename BasicJsonType, typename CompatibleArrayType>
void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priority_tag<2> /*unused*/) void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr,
priority_tag<0> /*unused*/)
{ {
for (std::size_t i = 0; i < N; ++i) using std::end;
std::transform(
j.begin(), j.end(), std::inserter(arr, end(arr)),
[](const BasicJsonType & i)
{ {
arr[i] = j.at(i).template get<T>(); // get<BasicJsonType>() returns *this, this won't call a from_json
} // method when value_type is BasicJsonType
return i.template get<typename CompatibleArrayType::value_type>();
});
} }
template < template <typename BasicJsonType, typename CompatibleArrayType,
typename BasicJsonType, typename CompatibleArrayType, enable_if_t <
enable_if_t < is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and
not std::is_same<typename BasicJsonType::array_t, not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
CompatibleArrayType>::value and not is_basic_json<CompatibleArrayType>::value,
std::is_constructible < int > = 0 >
BasicJsonType, typename CompatibleArrayType::value_type >::value,
int > = 0 > auto from_json(const BasicJsonType& j, CompatibleArrayType& arr)
void from_json(const BasicJsonType& j, CompatibleArrayType& arr) -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
j.template get<typename CompatibleArrayType::value_type>(),
void())
{ {
if (JSON_UNLIKELY(not j.is_array())) if (JSON_UNLIKELY(not j.is_array()))
{ {
@ -224,7 +227,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
std::string(j.type_name()))); std::string(j.type_name())));
} }
from_json_array_impl(j, arr, priority_tag<2> {}); from_json_array_impl(j, arr, priority_tag<3> {});
} }
template<typename BasicJsonType, typename CompatibleObjectType, template<typename BasicJsonType, typename CompatibleObjectType,
@ -347,35 +350,13 @@ void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyE
struct from_json_fn struct from_json_fn
{ {
private:
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const auto operator()(const BasicJsonType& j, T& val) const
noexcept(noexcept(from_json(j, val))) noexcept(noexcept(from_json(j, val)))
-> decltype(from_json(j, val), void()) -> decltype(from_json(j, val), void())
{ {
return from_json(j, val); return from_json(j, val);
} }
template<typename BasicJsonType, typename T>
void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept
{
static_assert(sizeof(BasicJsonType) == 0,
"could not find from_json() method in T's namespace");
#ifdef _MSC_VER
// MSVC does not show a stacktrace for the above assert
using decayed = uncvref_t<T>;
static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0,
"forcing MSVC stacktrace to show which T we're talking about.");
#endif
}
public:
template<typename BasicJsonType, typename T>
void operator()(const BasicJsonType& j, T& val) const
noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {})))
{
return call(j, val, priority_tag<1> {});
}
}; };
} }

View file

@ -248,10 +248,14 @@ void to_json(BasicJsonType& j, const std::vector<bool>& e)
external_constructor<value_t::array>::construct(j, e); external_constructor<value_t::array>::construct(j, e);
} }
template<typename BasicJsonType, typename CompatibleArrayType, template <typename BasicJsonType, typename CompatibleArrayType,
enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value or enable_if_t<is_compatible_array_type<BasicJsonType,
std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, CompatibleArrayType>::value and
int> = 0> not is_compatible_object_type<
BasicJsonType, CompatibleArrayType>::value and
not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
not is_basic_json<CompatibleArrayType>::value,
int> = 0>
void to_json(BasicJsonType& j, const CompatibleArrayType& arr) void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
external_constructor<value_t::array>::construct(j, arr); external_constructor<value_t::array>::construct(j, arr);
@ -271,7 +275,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
} }
template<typename BasicJsonType, typename CompatibleObjectType, template<typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0> enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>
void to_json(BasicJsonType& j, const CompatibleObjectType& obj) void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
external_constructor<value_t::object>::construct(j, obj); external_constructor<value_t::object>::construct(j, obj);
@ -283,9 +287,12 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
external_constructor<value_t::object>::construct(j, std::move(obj)); external_constructor<value_t::object>::construct(j, std::move(obj));
} }
template<typename BasicJsonType, typename T, std::size_t N, template <
enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, T (&)[N]>::value, int> = 0> typename BasicJsonType, typename T, std::size_t N,
void to_json(BasicJsonType& j, T (&arr)[N]) enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,
const T (&)[N]>::value,
int> = 0 >
void to_json(BasicJsonType& j, const T (&arr)[N])
{ {
external_constructor<value_t::array>::construct(j, arr); external_constructor<value_t::array>::construct(j, arr);
} }
@ -318,35 +325,12 @@ void to_json(BasicJsonType& j, const std::tuple<Args...>& t)
struct to_json_fn struct to_json_fn
{ {
private:
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
-> decltype(to_json(j, std::forward<T>(val)), void()) -> decltype(to_json(j, std::forward<T>(val)), void())
{ {
return to_json(j, std::forward<T>(val)); return to_json(j, std::forward<T>(val));
} }
template<typename BasicJsonType, typename T>
void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept
{
static_assert(sizeof(BasicJsonType) == 0,
"could not find to_json() method in T's namespace");
#ifdef _MSC_VER
// MSVC does not show a stacktrace for the above assert
using decayed = uncvref_t<T>;
static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0,
"forcing MSVC stacktrace to show which T we're talking about.");
#endif
}
public:
template<typename BasicJsonType, typename T>
void operator()(BasicJsonType& j, T&& val) const
noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {})))
{
return call(j, std::forward<T>(val), priority_tag<1> {});
}
}; };
} }

View file

@ -102,22 +102,3 @@
basic_json<ObjectType, ArrayType, StringType, BooleanType, \ basic_json<ObjectType, ArrayType, StringType, BooleanType, \
NumberIntegerType, NumberUnsignedType, NumberFloatType, \ NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer> AllocatorType, JSONSerializer>
/*!
@brief Helper to determine whether there's a key_type for T.
This helper is used to tell associative containers apart from other containers
such as sequence containers. For instance, `std::map` passes the test as it
contains a `mapped_type`, whereas `std::vector` fails the test.
@sa http://stackoverflow.com/a/7728728/266378
@since version 1.0.0, overworked in version 2.0.6
*/
#define NLOHMANN_JSON_HAS_HELPER(type) \
template<typename T> struct has_##type { \
template<typename U, typename = typename U::type> \
static int detect(U &&); \
static void detect(...); \
static constexpr bool value = \
std::is_integral<decltype(detect(std::declval<T>()))>::value; \
}

View file

@ -20,4 +20,3 @@
#undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_17
#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
#undef NLOHMANN_BASIC_JSON_TPL #undef NLOHMANN_BASIC_JSON_TPL
#undef NLOHMANN_JSON_HAS_HELPER

View file

@ -46,26 +46,6 @@ template<> struct make_index_sequence<1> : index_sequence<0> {};
template<typename... Ts> template<typename... Ts>
using index_sequence_for = make_index_sequence<sizeof...(Ts)>; using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
/*
Implementation of two C++17 constructs: conjunction, negation. This is needed
to avoid evaluating all the traits in a condition
For example: not std::is_same<void, T>::value and has_value_type<T>::value
will not compile when T = void (on MSVC at least). Whereas
conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will
stop evaluating if negation<...>::value == false
Please note that those constructs must be used with caution, since symbols can
become very long quickly (which can slow down compilation and cause MSVC
internal compiler errors). Only use it when you have to (see example ahead).
*/
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<class B> struct negation : std::integral_constant<bool, not B::value> {};
// dispatch utility (taken from ranges-v3) // dispatch utility (taken from ranges-v3)
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
template<> struct priority_tag<0> {}; template<> struct priority_tag<0> {};

View file

@ -7,6 +7,7 @@
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
namespace nlohmann namespace nlohmann
@ -30,9 +31,61 @@ template<typename> struct is_basic_json : std::false_type {};
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
//////////////////////// //////////////////////////
// has_/is_ functions // // aliases for detected //
//////////////////////// //////////////////////////
template <typename T>
using mapped_type_t = typename T::mapped_type;
template <typename T>
using key_type_t = typename T::key_type;
template <typename T>
using value_type_t = typename T::value_type;
template <typename T>
using difference_type_t = typename T::difference_type;
template <typename T>
using pointer_t = typename T::pointer;
template <typename T>
using reference_t = typename T::reference;
template <typename T>
using iterator_category_t = typename T::iterator_category;
template <typename T>
using iterator_t = typename T::iterator;
template <typename T, typename... Args>
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>()...));
///////////////////
// is_ functions //
///////////////////
template <typename T, typename = void>
struct is_iterator_traits : std::false_type {};
template <typename T>
struct is_iterator_traits<std::iterator_traits<T>>
{
private:
using traits = std::iterator_traits<T>;
public:
static constexpr auto value =
is_detected<value_type_t, traits>::value &&
is_detected<difference_type_t, traits>::value &&
is_detected<pointer_t, traits>::value &&
is_detected<iterator_category_t, traits>::value &&
is_detected<reference_t, traits>::value;
};
// source: https://stackoverflow.com/a/37193089/4116453 // source: https://stackoverflow.com/a/37193089/4116453
@ -42,113 +95,104 @@ struct is_complete_type : std::false_type {};
template <typename T> template <typename T>
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
NLOHMANN_JSON_HAS_HELPER(mapped_type); template <typename BasicJsonType, typename CompatibleObjectType,
NLOHMANN_JSON_HAS_HELPER(key_type); typename = void>
NLOHMANN_JSON_HAS_HELPER(value_type);
NLOHMANN_JSON_HAS_HELPER(iterator);
template<bool B, class RealType, class CompatibleObjectType>
struct is_compatible_object_type_impl : std::false_type {}; struct is_compatible_object_type_impl : std::false_type {};
template<class RealType, class CompatibleObjectType> template <typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType> struct is_compatible_object_type_impl <
BasicJsonType, CompatibleObjectType,
enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and
is_detected<key_type_t, CompatibleObjectType>::value >>
{ {
static constexpr auto value =
std::is_constructible<typename RealType::key_type, typename CompatibleObjectType::key_type>::value and using object_t = typename BasicJsonType::object_t;
std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value;
// macOS's is_constructible does not play well with nonesuch...
static constexpr bool value =
std::is_constructible<typename object_t::key_type,
typename CompatibleObjectType::key_type>::value and
std::is_constructible<typename object_t::mapped_type,
typename CompatibleObjectType::mapped_type>::value;
}; };
template<bool B, class RealType, class CompatibleStringType> template <typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type
: is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
template <typename BasicJsonType, typename CompatibleStringType,
typename = void>
struct is_compatible_string_type_impl : std::false_type {}; struct is_compatible_string_type_impl : std::false_type {};
template<class RealType, class CompatibleStringType> template <typename BasicJsonType, typename CompatibleStringType>
struct is_compatible_string_type_impl<true, RealType, CompatibleStringType> struct is_compatible_string_type_impl <
BasicJsonType, CompatibleStringType,
enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
value_type_t, CompatibleStringType>::value >>
{ {
static constexpr auto value = static constexpr auto value =
std::is_same<typename RealType::value_type, typename CompatibleStringType::value_type>::value and std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
std::is_constructible<RealType, CompatibleStringType>::value;
}; };
template<class BasicJsonType, class CompatibleObjectType> template <typename BasicJsonType, typename CompatibleStringType>
struct is_compatible_object_type
{
static auto constexpr value = is_compatible_object_type_impl <
conjunction<negation<std::is_same<void, CompatibleObjectType>>,
has_mapped_type<CompatibleObjectType>,
has_key_type<CompatibleObjectType>>::value,
typename BasicJsonType::object_t, CompatibleObjectType >::value;
};
template<class BasicJsonType, class CompatibleStringType>
struct is_compatible_string_type struct is_compatible_string_type
: is_compatible_string_type_impl<BasicJsonType, CompatibleStringType> {};
template <typename BasicJsonType, typename CompatibleArrayType, typename = void>
struct is_compatible_array_type_impl : std::false_type {};
template <typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type_impl <
BasicJsonType, CompatibleArrayType,
enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and
is_detected<iterator_t, CompatibleArrayType>::value >>
{ {
static auto constexpr value = is_compatible_string_type_impl < // This is needed because json_reverse_iterator has a ::iterator type...
conjunction<negation<std::is_same<void, CompatibleStringType>>, // Therefore it is detected as a CompatibleArrayType.
has_value_type<CompatibleStringType>>::value, // The real fix would be to have an Iterable concept.
typename BasicJsonType::string_t, CompatibleStringType >::value; static constexpr bool value = not is_iterator_traits<std::iterator_traits<CompatibleArrayType>>::value;
}; };
template<typename BasicJsonType, typename T> template <typename BasicJsonType, typename CompatibleArrayType>
struct is_basic_json_nested_type
{
static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or
std::is_same<T, typename BasicJsonType::const_iterator>::value or
std::is_same<T, typename BasicJsonType::reverse_iterator>::value or
std::is_same<T, typename BasicJsonType::const_reverse_iterator>::value;
};
template<class BasicJsonType, class CompatibleArrayType>
struct is_compatible_array_type struct is_compatible_array_type
{ : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
static auto constexpr value =
conjunction<negation<std::is_same<void, CompatibleArrayType>>,
negation<is_compatible_object_type<
BasicJsonType, CompatibleArrayType>>,
negation<std::is_constructible<typename BasicJsonType::string_t,
CompatibleArrayType>>,
negation<is_basic_json_nested_type<BasicJsonType, CompatibleArrayType>>,
has_value_type<CompatibleArrayType>,
has_iterator<CompatibleArrayType>>::value;
};
template<bool, typename, typename> template <typename RealIntegerType, typename CompatibleNumberIntegerType,
typename = void>
struct is_compatible_integer_type_impl : std::false_type {}; struct is_compatible_integer_type_impl : std::false_type {};
template<typename RealIntegerType, typename CompatibleNumberIntegerType> template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType> struct is_compatible_integer_type_impl <
RealIntegerType, CompatibleNumberIntegerType,
enable_if_t<std::is_integral<RealIntegerType>::value and
std::is_integral<CompatibleNumberIntegerType>::value and
not std::is_same<bool, CompatibleNumberIntegerType>::value >>
{ {
// is there an assert somewhere on overflows? // is there an assert somewhere on overflows?
using RealLimits = std::numeric_limits<RealIntegerType>; using RealLimits = std::numeric_limits<RealIntegerType>;
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
static constexpr auto value = static constexpr auto value =
std::is_constructible<RealIntegerType, CompatibleNumberIntegerType>::value and std::is_constructible<RealIntegerType,
CompatibleNumberIntegerType>::value and
CompatibleLimits::is_integer and CompatibleLimits::is_integer and
RealLimits::is_signed == CompatibleLimits::is_signed; RealLimits::is_signed == CompatibleLimits::is_signed;
}; };
template<typename RealIntegerType, typename CompatibleNumberIntegerType> template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type struct is_compatible_integer_type
{ : is_compatible_integer_type_impl<RealIntegerType,
static constexpr auto value = CompatibleNumberIntegerType> {};
is_compatible_integer_type_impl <
std::is_integral<CompatibleNumberIntegerType>::value and
not std::is_same<bool, 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
{ {
// also check the return type of from_json using serializer = typename BasicJsonType::template json_serializer<T, void>;
template<typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json(
std::declval<BasicJsonType>(), std::declval<T&>()))>::value>>
static int detect(U&&);
static void detect(...);
static constexpr bool value = std::is_integral<decltype( static constexpr bool value =
detect(std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; is_detected_exact<void, from_json_function, serializer,
const BasicJsonType&, T&>::value;
}; };
// This trait checks if JSONSerializer<T>::from_json(json const&) exists // This trait checks if JSONSerializer<T>::from_json(json const&) exists
@ -156,45 +200,38 @@ struct has_from_json
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_non_default_from_json struct has_non_default_from_json
{ {
template < using serializer = typename BasicJsonType::template json_serializer<T, void>;
typename U,
typename = enable_if_t<std::is_same<
T, decltype(uncvref_t<U>::from_json(std::declval<BasicJsonType>()))>::value >>
static int detect(U&&);
static void detect(...);
static constexpr bool value = std::is_integral<decltype(detect( static constexpr bool value =
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; is_detected_exact<T, from_json_function, serializer,
const BasicJsonType&>::value;
}; };
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists // This trait checks if BasicJsonType::json_serializer<T>::to_json exists
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_to_json struct has_to_json
{ {
template<typename U, typename = decltype(uncvref_t<U>::to_json( using serializer = typename BasicJsonType::template json_serializer<T, void>;
std::declval<BasicJsonType&>(), std::declval<T>()))>
static int detect(U&&);
static void detect(...);
static constexpr bool value = std::is_integral<decltype(detect( static constexpr bool value =
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
T>::value;
}; };
template <typename BasicJsonType, typename CompatibleCompleteType> template <typename BasicJsonType, typename CompatibleType, typename = void>
struct is_compatible_complete_type struct is_compatible_type_impl: std::false_type {};
template <typename BasicJsonType, typename CompatibleType>
struct is_compatible_type_impl <
BasicJsonType, CompatibleType,
enable_if_t<is_complete_type<CompatibleType>::value >>
{ {
static constexpr bool value = static constexpr bool value =
not std::is_base_of<std::istream, CompatibleCompleteType>::value and has_to_json<BasicJsonType, CompatibleType>::value;
not is_basic_json<CompatibleCompleteType>::value and
not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
}; };
template <typename BasicJsonType, typename CompatibleType> template <typename BasicJsonType, typename CompatibleType>
struct is_compatible_type struct is_compatible_type
: conjunction<is_complete_type<CompatibleType>, : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
is_compatible_complete_type<BasicJsonType, CompatibleType>>
{
};
} }
} }

View file

@ -4,7 +4,10 @@ namespace nlohmann
{ {
namespace detail namespace detail
{ {
template <typename...> template <typename ...Ts> struct make_void
using void_t = void; {
using type = void;
};
template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
} }
} }

View file

@ -1243,7 +1243,7 @@ class basic_json
template <typename CompatibleType, template <typename CompatibleType,
typename U = detail::uncvref_t<CompatibleType>, typename U = detail::uncvref_t<CompatibleType>,
detail::enable_if_t< detail::enable_if_t<
detail::is_compatible_type<basic_json_t, U>::value, int> = 0> not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
basic_json(CompatibleType && val) noexcept(noexcept( basic_json(CompatibleType && val) noexcept(noexcept(
JSONSerializer<U>::to_json(std::declval<basic_json_t&>(), JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
std::forward<CompatibleType>(val)))) std::forward<CompatibleType>(val))))

View file

@ -218,25 +218,6 @@ using json = basic_json<>;
NumberIntegerType, NumberUnsignedType, NumberFloatType, \ NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer> AllocatorType, JSONSerializer>
/*!
@brief Helper to determine whether there's a key_type for T.
This helper is used to tell associative containers apart from other containers
such as sequence containers. For instance, `std::map` passes the test as it
contains a `mapped_type`, whereas `std::vector` fails the test.
@sa http://stackoverflow.com/a/7728728/266378
@since version 1.0.0, overworked in version 2.0.6
*/
#define NLOHMANN_JSON_HAS_HELPER(type) \
template<typename T> struct has_##type { \
template<typename U, typename = typename U::type> \
static int detect(U &&); \
static void detect(...); \
static constexpr bool value = \
std::is_integral<decltype(detect(std::declval<T>()))>::value; \
}
// #include <nlohmann/detail/meta/cpp_future.hpp> // #include <nlohmann/detail/meta/cpp_future.hpp>
@ -286,26 +267,6 @@ template<> struct make_index_sequence<1> : index_sequence<0> {};
template<typename... Ts> template<typename... Ts>
using index_sequence_for = make_index_sequence<sizeof...(Ts)>; using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
/*
Implementation of two C++17 constructs: conjunction, negation. This is needed
to avoid evaluating all the traits in a condition
For example: not std::is_same<void, T>::value and has_value_type<T>::value
will not compile when T = void (on MSVC at least). Whereas
conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will
stop evaluating if negation<...>::value == false
Please note that those constructs must be used with caution, since symbols can
become very long quickly (which can slow down compilation and cause MSVC
internal compiler errors). Only use it when you have to (see example ahead).
*/
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<class B> struct negation : std::integral_constant<bool, not B::value> {};
// dispatch utility (taken from ranges-v3) // dispatch utility (taken from ranges-v3)
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
template<> struct priority_tag<0> {}; template<> struct priority_tag<0> {};
@ -334,6 +295,78 @@ constexpr T static_const<T>::value;
// #include <nlohmann/detail/meta/cpp_future.hpp> // #include <nlohmann/detail/meta/cpp_future.hpp>
// #include <nlohmann/detail/meta/detected.hpp>
#include <type_traits>
// #include <nlohmann/detail/meta/void_t.hpp>
namespace nlohmann
{
namespace detail
{
template <typename ...Ts> struct make_void
{
using type = void;
};
template <typename ...Ts> using void_t = typename make_void<Ts...>::type;
}
}
// http://en.cppreference.com/w/cpp/experimental/is_detected
namespace nlohmann
{
namespace detail
{
struct nonesuch
{
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
template <class Default,
class AlwaysVoid,
template <class...> class Op,
class... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
template <class Default, template <class...> class Op, class... Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
{
using value_t = std::true_type;
using type = 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>
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
template <class Default, template <class...> class Op, class... Args>
using detected_or = detector<Default, void, Op, Args...>;
template <class Default, template <class...> class Op, class... Args>
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
template <class Expected, template <class...> class Op, class... Args>
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
template <class To, template <class...> class Op, class... Args>
using is_detected_convertible =
std::is_convertible<detected_t<Op, Args...>, To>;
}
}
// #include <nlohmann/detail/macro_scope.hpp> // #include <nlohmann/detail/macro_scope.hpp>
@ -358,9 +391,61 @@ template<typename> struct is_basic_json : std::false_type {};
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
//////////////////////// //////////////////////////
// has_/is_ functions // // aliases for detected //
//////////////////////// //////////////////////////
template <typename T>
using mapped_type_t = typename T::mapped_type;
template <typename T>
using key_type_t = typename T::key_type;
template <typename T>
using value_type_t = typename T::value_type;
template <typename T>
using difference_type_t = typename T::difference_type;
template <typename T>
using pointer_t = typename T::pointer;
template <typename T>
using reference_t = typename T::reference;
template <typename T>
using iterator_category_t = typename T::iterator_category;
template <typename T>
using iterator_t = typename T::iterator;
template <typename T, typename... Args>
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>()...));
///////////////////
// is_ functions //
///////////////////
template <typename T, typename = void>
struct is_iterator_traits : std::false_type {};
template <typename T>
struct is_iterator_traits<std::iterator_traits<T>>
{
private:
using traits = std::iterator_traits<T>;
public:
static constexpr auto value =
is_detected<value_type_t, traits>::value &&
is_detected<difference_type_t, traits>::value &&
is_detected<pointer_t, traits>::value &&
is_detected<iterator_category_t, traits>::value &&
is_detected<reference_t, traits>::value;
};
// source: https://stackoverflow.com/a/37193089/4116453 // source: https://stackoverflow.com/a/37193089/4116453
@ -370,113 +455,104 @@ struct is_complete_type : std::false_type {};
template <typename T> template <typename T>
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
NLOHMANN_JSON_HAS_HELPER(mapped_type); template <typename BasicJsonType, typename CompatibleObjectType,
NLOHMANN_JSON_HAS_HELPER(key_type); typename = void>
NLOHMANN_JSON_HAS_HELPER(value_type);
NLOHMANN_JSON_HAS_HELPER(iterator);
template<bool B, class RealType, class CompatibleObjectType>
struct is_compatible_object_type_impl : std::false_type {}; struct is_compatible_object_type_impl : std::false_type {};
template<class RealType, class CompatibleObjectType> template <typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType> struct is_compatible_object_type_impl <
BasicJsonType, CompatibleObjectType,
enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and
is_detected<key_type_t, CompatibleObjectType>::value >>
{ {
static constexpr auto value =
std::is_constructible<typename RealType::key_type, typename CompatibleObjectType::key_type>::value and using object_t = typename BasicJsonType::object_t;
std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value;
// macOS's is_constructible does not play well with nonesuch...
static constexpr bool value =
std::is_constructible<typename object_t::key_type,
typename CompatibleObjectType::key_type>::value and
std::is_constructible<typename object_t::mapped_type,
typename CompatibleObjectType::mapped_type>::value;
}; };
template<bool B, class RealType, class CompatibleStringType> template <typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type
: is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
template <typename BasicJsonType, typename CompatibleStringType,
typename = void>
struct is_compatible_string_type_impl : std::false_type {}; struct is_compatible_string_type_impl : std::false_type {};
template<class RealType, class CompatibleStringType> template <typename BasicJsonType, typename CompatibleStringType>
struct is_compatible_string_type_impl<true, RealType, CompatibleStringType> struct is_compatible_string_type_impl <
BasicJsonType, CompatibleStringType,
enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,
value_type_t, CompatibleStringType>::value >>
{ {
static constexpr auto value = static constexpr auto value =
std::is_same<typename RealType::value_type, typename CompatibleStringType::value_type>::value and std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;
std::is_constructible<RealType, CompatibleStringType>::value;
}; };
template<class BasicJsonType, class CompatibleObjectType> template <typename BasicJsonType, typename CompatibleStringType>
struct is_compatible_object_type
{
static auto constexpr value = is_compatible_object_type_impl <
conjunction<negation<std::is_same<void, CompatibleObjectType>>,
has_mapped_type<CompatibleObjectType>,
has_key_type<CompatibleObjectType>>::value,
typename BasicJsonType::object_t, CompatibleObjectType >::value;
};
template<class BasicJsonType, class CompatibleStringType>
struct is_compatible_string_type struct is_compatible_string_type
: is_compatible_string_type_impl<BasicJsonType, CompatibleStringType> {};
template <typename BasicJsonType, typename CompatibleArrayType, typename = void>
struct is_compatible_array_type_impl : std::false_type {};
template <typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type_impl <
BasicJsonType, CompatibleArrayType,
enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and
is_detected<iterator_t, CompatibleArrayType>::value >>
{ {
static auto constexpr value = is_compatible_string_type_impl < // This is needed because json_reverse_iterator has a ::iterator type...
conjunction<negation<std::is_same<void, CompatibleStringType>>, // Therefore it is detected as a CompatibleArrayType.
has_value_type<CompatibleStringType>>::value, // The real fix would be to have an Iterable concept.
typename BasicJsonType::string_t, CompatibleStringType >::value; static constexpr bool value = not is_iterator_traits<std::iterator_traits<CompatibleArrayType>>::value;
}; };
template<typename BasicJsonType, typename T> template <typename BasicJsonType, typename CompatibleArrayType>
struct is_basic_json_nested_type
{
static auto constexpr value = std::is_same<T, typename BasicJsonType::iterator>::value or
std::is_same<T, typename BasicJsonType::const_iterator>::value or
std::is_same<T, typename BasicJsonType::reverse_iterator>::value or
std::is_same<T, typename BasicJsonType::const_reverse_iterator>::value;
};
template<class BasicJsonType, class CompatibleArrayType>
struct is_compatible_array_type struct is_compatible_array_type
{ : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
static auto constexpr value =
conjunction<negation<std::is_same<void, CompatibleArrayType>>,
negation<is_compatible_object_type<
BasicJsonType, CompatibleArrayType>>,
negation<std::is_constructible<typename BasicJsonType::string_t,
CompatibleArrayType>>,
negation<is_basic_json_nested_type<BasicJsonType, CompatibleArrayType>>,
has_value_type<CompatibleArrayType>,
has_iterator<CompatibleArrayType>>::value;
};
template<bool, typename, typename> template <typename RealIntegerType, typename CompatibleNumberIntegerType,
typename = void>
struct is_compatible_integer_type_impl : std::false_type {}; struct is_compatible_integer_type_impl : std::false_type {};
template<typename RealIntegerType, typename CompatibleNumberIntegerType> template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl<true, RealIntegerType, CompatibleNumberIntegerType> struct is_compatible_integer_type_impl <
RealIntegerType, CompatibleNumberIntegerType,
enable_if_t<std::is_integral<RealIntegerType>::value and
std::is_integral<CompatibleNumberIntegerType>::value and
not std::is_same<bool, CompatibleNumberIntegerType>::value >>
{ {
// is there an assert somewhere on overflows? // is there an assert somewhere on overflows?
using RealLimits = std::numeric_limits<RealIntegerType>; using RealLimits = std::numeric_limits<RealIntegerType>;
using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>; using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
static constexpr auto value = static constexpr auto value =
std::is_constructible<RealIntegerType, CompatibleNumberIntegerType>::value and std::is_constructible<RealIntegerType,
CompatibleNumberIntegerType>::value and
CompatibleLimits::is_integer and CompatibleLimits::is_integer and
RealLimits::is_signed == CompatibleLimits::is_signed; RealLimits::is_signed == CompatibleLimits::is_signed;
}; };
template<typename RealIntegerType, typename CompatibleNumberIntegerType> template <typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type struct is_compatible_integer_type
{ : is_compatible_integer_type_impl<RealIntegerType,
static constexpr auto value = CompatibleNumberIntegerType> {};
is_compatible_integer_type_impl <
std::is_integral<CompatibleNumberIntegerType>::value and
not std::is_same<bool, 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
{ {
// also check the return type of from_json using serializer = typename BasicJsonType::template json_serializer<T, void>;
template<typename U, typename = enable_if_t<std::is_same<void, decltype(uncvref_t<U>::from_json(
std::declval<BasicJsonType>(), std::declval<T&>()))>::value>>
static int detect(U&&);
static void detect(...);
static constexpr bool value = std::is_integral<decltype( static constexpr bool value =
detect(std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; is_detected_exact<void, from_json_function, serializer,
const BasicJsonType&, T&>::value;
}; };
// This trait checks if JSONSerializer<T>::from_json(json const&) exists // This trait checks if JSONSerializer<T>::from_json(json const&) exists
@ -484,46 +560,39 @@ struct has_from_json
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_non_default_from_json struct has_non_default_from_json
{ {
template < using serializer = typename BasicJsonType::template json_serializer<T, void>;
typename U,
typename = enable_if_t<std::is_same<
T, decltype(uncvref_t<U>::from_json(std::declval<BasicJsonType>()))>::value >>
static int detect(U&&);
static void detect(...);
static constexpr bool value = std::is_integral<decltype(detect( static constexpr bool value =
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; is_detected_exact<T, from_json_function, serializer,
const BasicJsonType&>::value;
}; };
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists // This trait checks if BasicJsonType::json_serializer<T>::to_json exists
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_to_json struct has_to_json
{ {
template<typename U, typename = decltype(uncvref_t<U>::to_json( using serializer = typename BasicJsonType::template json_serializer<T, void>;
std::declval<BasicJsonType&>(), std::declval<T>()))>
static int detect(U&&);
static void detect(...);
static constexpr bool value = std::is_integral<decltype(detect( static constexpr bool value =
std::declval<typename BasicJsonType::template json_serializer<T, void>>()))>::value; is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
T>::value;
}; };
template <typename BasicJsonType, typename CompatibleCompleteType> template <typename BasicJsonType, typename CompatibleType, typename = void>
struct is_compatible_complete_type struct is_compatible_type_impl: std::false_type {};
template <typename BasicJsonType, typename CompatibleType>
struct is_compatible_type_impl <
BasicJsonType, CompatibleType,
enable_if_t<is_complete_type<CompatibleType>::value >>
{ {
static constexpr bool value = static constexpr bool value =
not std::is_base_of<std::istream, CompatibleCompleteType>::value and has_to_json<BasicJsonType, CompatibleType>::value;
not is_basic_json<CompatibleCompleteType>::value and
not is_basic_json_nested_type<BasicJsonType, CompatibleCompleteType>::value and
has_to_json<BasicJsonType, CompatibleCompleteType>::value;
}; };
template <typename BasicJsonType, typename CompatibleType> template <typename BasicJsonType, typename CompatibleType>
struct is_compatible_type struct is_compatible_type
: conjunction<is_complete_type<CompatibleType>, : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
is_compatible_complete_type<BasicJsonType, CompatibleType>>
{
};
} }
} }
@ -1072,16 +1141,6 @@ void from_json(const BasicJsonType& j, EnumType& e)
e = static_cast<EnumType>(val); e = static_cast<EnumType>(val);
} }
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr)
{
if (JSON_UNLIKELY(not j.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
}
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
}
// forward_list doesn't have an insert method // forward_list doesn't have an insert method
template<typename BasicJsonType, typename T, typename Allocator, template<typename BasicJsonType, typename T, typename Allocator,
enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0> enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>
@ -1111,24 +1170,28 @@ void from_json(const BasicJsonType& j, std::valarray<T>& l)
std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l));
} }
template<typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType>
void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
{ {
using std::end; arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
}
std::transform(j.begin(), j.end(), template <typename BasicJsonType, typename T, std::size_t N>
std::inserter(arr, end(arr)), [](const BasicJsonType & i) auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
priority_tag<2> /*unused*/)
-> decltype(j.template get<T>(), void())
{
for (std::size_t i = 0; i < N; ++i)
{ {
// get<BasicJsonType>() returns *this, this won't call a from_json arr[i] = j.at(i).template get<T>();
// method when value_type is BasicJsonType }
return i.template get<typename CompatibleArrayType::value_type>();
});
} }
template<typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/)
-> decltype( -> decltype(
arr.reserve(std::declval<typename CompatibleArrayType::size_type>()), arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
j.template get<typename CompatibleArrayType::value_type>(),
void()) void())
{ {
using std::end; using std::end;
@ -1143,25 +1206,34 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio
}); });
} }
template<typename BasicJsonType, typename T, std::size_t N> template <typename BasicJsonType, typename CompatibleArrayType>
void from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priority_tag<2> /*unused*/) void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr,
priority_tag<0> /*unused*/)
{ {
for (std::size_t i = 0; i < N; ++i) using std::end;
std::transform(
j.begin(), j.end(), std::inserter(arr, end(arr)),
[](const BasicJsonType & i)
{ {
arr[i] = j.at(i).template get<T>(); // get<BasicJsonType>() returns *this, this won't call a from_json
} // method when value_type is BasicJsonType
return i.template get<typename CompatibleArrayType::value_type>();
});
} }
template < template <typename BasicJsonType, typename CompatibleArrayType,
typename BasicJsonType, typename CompatibleArrayType, enable_if_t <
enable_if_t < is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and
not std::is_same<typename BasicJsonType::array_t, not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
CompatibleArrayType>::value and not is_basic_json<CompatibleArrayType>::value,
std::is_constructible < int > = 0 >
BasicJsonType, typename CompatibleArrayType::value_type >::value,
int > = 0 > auto from_json(const BasicJsonType& j, CompatibleArrayType& arr)
void from_json(const BasicJsonType& j, CompatibleArrayType& arr) -> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
j.template get<typename CompatibleArrayType::value_type>(),
void())
{ {
if (JSON_UNLIKELY(not j.is_array())) if (JSON_UNLIKELY(not j.is_array()))
{ {
@ -1169,7 +1241,7 @@ void from_json(const BasicJsonType& j, CompatibleArrayType& arr)
std::string(j.type_name()))); std::string(j.type_name())));
} }
from_json_array_impl(j, arr, priority_tag<2> {}); from_json_array_impl(j, arr, priority_tag<3> {});
} }
template<typename BasicJsonType, typename CompatibleObjectType, template<typename BasicJsonType, typename CompatibleObjectType,
@ -1292,35 +1364,13 @@ void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyE
struct from_json_fn struct from_json_fn
{ {
private:
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const auto operator()(const BasicJsonType& j, T& val) const
noexcept(noexcept(from_json(j, val))) noexcept(noexcept(from_json(j, val)))
-> decltype(from_json(j, val), void()) -> decltype(from_json(j, val), void())
{ {
return from_json(j, val); return from_json(j, val);
} }
template<typename BasicJsonType, typename T>
void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept
{
static_assert(sizeof(BasicJsonType) == 0,
"could not find from_json() method in T's namespace");
#ifdef _MSC_VER
// MSVC does not show a stacktrace for the above assert
using decayed = uncvref_t<T>;
static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0,
"forcing MSVC stacktrace to show which T we're talking about.");
#endif
}
public:
template<typename BasicJsonType, typename T>
void operator()(const BasicJsonType& j, T& val) const
noexcept(noexcept(std::declval<from_json_fn>().call(j, val, priority_tag<1> {})))
{
return call(j, val, priority_tag<1> {});
}
}; };
} }
@ -1717,10 +1767,14 @@ void to_json(BasicJsonType& j, const std::vector<bool>& e)
external_constructor<value_t::array>::construct(j, e); external_constructor<value_t::array>::construct(j, e);
} }
template<typename BasicJsonType, typename CompatibleArrayType, template <typename BasicJsonType, typename CompatibleArrayType,
enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value or enable_if_t<is_compatible_array_type<BasicJsonType,
std::is_same<typename BasicJsonType::array_t, CompatibleArrayType>::value, CompatibleArrayType>::value and
int> = 0> not is_compatible_object_type<
BasicJsonType, CompatibleArrayType>::value and
not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
not is_basic_json<CompatibleArrayType>::value,
int> = 0>
void to_json(BasicJsonType& j, const CompatibleArrayType& arr) void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
external_constructor<value_t::array>::construct(j, arr); external_constructor<value_t::array>::construct(j, arr);
@ -1740,7 +1794,7 @@ void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
} }
template<typename BasicJsonType, typename CompatibleObjectType, template<typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0> enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>
void to_json(BasicJsonType& j, const CompatibleObjectType& obj) void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
external_constructor<value_t::object>::construct(j, obj); external_constructor<value_t::object>::construct(j, obj);
@ -1752,9 +1806,12 @@ void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
external_constructor<value_t::object>::construct(j, std::move(obj)); external_constructor<value_t::object>::construct(j, std::move(obj));
} }
template<typename BasicJsonType, typename T, std::size_t N, template <
enable_if_t<not std::is_constructible<typename BasicJsonType::string_t, T (&)[N]>::value, int> = 0> typename BasicJsonType, typename T, std::size_t N,
void to_json(BasicJsonType& j, T (&arr)[N]) enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,
const T (&)[N]>::value,
int> = 0 >
void to_json(BasicJsonType& j, const T (&arr)[N])
{ {
external_constructor<value_t::array>::construct(j, arr); external_constructor<value_t::array>::construct(j, arr);
} }
@ -1787,35 +1844,12 @@ void to_json(BasicJsonType& j, const std::tuple<Args...>& t)
struct to_json_fn struct to_json_fn
{ {
private:
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
-> decltype(to_json(j, std::forward<T>(val)), void()) -> decltype(to_json(j, std::forward<T>(val)), void())
{ {
return to_json(j, std::forward<T>(val)); return to_json(j, std::forward<T>(val));
} }
template<typename BasicJsonType, typename T>
void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept
{
static_assert(sizeof(BasicJsonType) == 0,
"could not find to_json() method in T's namespace");
#ifdef _MSC_VER
// MSVC does not show a stacktrace for the above assert
using decayed = uncvref_t<T>;
static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0,
"forcing MSVC stacktrace to show which T we're talking about.");
#endif
}
public:
template<typename BasicJsonType, typename T>
void operator()(BasicJsonType& j, T&& val) const
noexcept(noexcept(std::declval<to_json_fn>().call(j, std::forward<T>(val), priority_tag<1> {})))
{
return call(j, std::forward<T>(val), priority_tag<1> {});
}
}; };
} }
@ -3562,73 +3596,6 @@ scan_number_done:
// #include <nlohmann/detail/meta/detected.hpp> // #include <nlohmann/detail/meta/detected.hpp>
#include <type_traits>
// #include <nlohmann/detail/meta/void_t.hpp>
namespace nlohmann
{
namespace detail
{
template <typename...>
using void_t = void;
}
}
// http://en.cppreference.com/w/cpp/experimental/is_detected
namespace nlohmann
{
namespace detail
{
struct nonesuch
{
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
template <class Default,
class AlwaysVoid,
template <class...> class Op,
class... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
template <class Default, template <class...> class Op, class... Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
{
using value_t = std::true_type;
using type = 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>
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
template <class Default, template <class...> class Op, class... Args>
using detected_or = detector<Default, void, Op, Args...>;
template <class Default, template <class...> class Op, class... Args>
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
template <class Expected, template <class...> class Op, class... Args>
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
template <class To, template <class...> class Op, class... Args>
using is_detected_convertible =
std::is_convertible<detected_t<Op, Args...>, To>;
}
}
// #include <nlohmann/detail/meta/type_traits.hpp> // #include <nlohmann/detail/meta/type_traits.hpp>
@ -11144,8 +11111,10 @@ struct adl_serializer
@param[in,out] val value to write to @param[in,out] val value to write to
*/ */
template<typename BasicJsonType, typename ValueType> template<typename BasicJsonType, typename ValueType>
static void from_json(BasicJsonType&& j, ValueType& val) noexcept( static auto from_json(BasicJsonType&& j, ValueType& val) noexcept(
noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) -> decltype(
::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void()
)
{ {
::nlohmann::from_json(std::forward<BasicJsonType>(j), val); ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
} }
@ -11159,9 +11128,11 @@ struct adl_serializer
@param[in,out] j JSON value to write to @param[in,out] j JSON value to write to
@param[in] val value to read from @param[in] val value to read from
*/ */
template<typename BasicJsonType, typename ValueType> template <typename BasicJsonType, typename ValueType>
static void to_json(BasicJsonType& j, ValueType&& val) noexcept( static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(
noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val)))) noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))
-> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)),
void())
{ {
::nlohmann::to_json(j, std::forward<ValueType>(val)); ::nlohmann::to_json(j, std::forward<ValueType>(val));
} }
@ -12342,7 +12313,7 @@ class basic_json
template <typename CompatibleType, template <typename CompatibleType,
typename U = detail::uncvref_t<CompatibleType>, typename U = detail::uncvref_t<CompatibleType>,
detail::enable_if_t< detail::enable_if_t<
detail::is_compatible_type<basic_json_t, U>::value, int> = 0> not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0>
basic_json(CompatibleType && val) noexcept(noexcept( basic_json(CompatibleType && val) noexcept(noexcept(
JSONSerializer<U>::to_json(std::declval<basic_json_t&>(), JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
std::forward<CompatibleType>(val)))) std::forward<CompatibleType>(val))))
@ -18899,7 +18870,6 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std
#undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_17
#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
#undef NLOHMANN_BASIC_JSON_TPL #undef NLOHMANN_BASIC_JSON_TPL
#undef NLOHMANN_JSON_HAS_HELPER
#endif #endif

View file

@ -317,8 +317,8 @@ TEST_CASE("object inspection")
SECTION("round trips") SECTION("round trips")
{ {
for (const auto& s : for (const auto& s :
{"3.141592653589793", "1000000000000000010E5" {"3.141592653589793", "1000000000000000010E5"
}) })
{ {
json j1 = json::parse(s); json j1 = json::parse(s);
std::string s1 = j1.dump(); std::string s1 = j1.dump();