add new is_constructible_* traits used in from_json

is_compatible_* traits were used in from_json, but it made no sense
whatsoever.

It used to work because of non-SFINAE correctness + json_ref
unconstrained variadic template constructor.

SFINAE checks are becoming quite complex, we need a specification of
some sort describing:

* which concepts the library uses
* how the conversion to/from json works in detail

Having such a specification would really help simplifying the current
code (as well as having meaningful checks).

Fixes !1299
parent dd672939
......@@ -84,13 +84,13 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
}
template <
typename BasicJsonType, typename CompatibleStringType,
typename BasicJsonType, typename ConstructibleStringType,
enable_if_t <
is_compatible_string_type<BasicJsonType, CompatibleStringType>::value and
is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value and
not std::is_same<typename BasicJsonType::string_t,
CompatibleStringType>::value,
ConstructibleStringType>::value,
int > = 0 >
void from_json(const BasicJsonType& j, CompatibleStringType& s)
void from_json(const BasicJsonType& j, ConstructibleStringType& s)
{
if (JSON_UNLIKELY(not j.is_string()))
{
......@@ -173,11 +173,11 @@ auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
}
}
template<typename BasicJsonType, typename CompatibleArrayType>
auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/)
template<typename BasicJsonType, typename ConstructibleArrayType>
auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
-> decltype(
arr.reserve(std::declval<typename CompatibleArrayType::size_type>()),
j.template get<typename CompatibleArrayType::value_type>(),
arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
j.template get<typename ConstructibleArrayType::value_type>(),
void())
{
using std::end;
......@@ -188,12 +188,12 @@ auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, prio
{
// 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>();
return i.template get<typename ConstructibleArrayType::value_type>();
});
}
template <typename BasicJsonType, typename CompatibleArrayType>
void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr,
template <typename BasicJsonType, typename ConstructibleArrayType>
void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
priority_tag<0> /*unused*/)
{
using std::end;
......@@ -204,21 +204,21 @@ void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr,
{
// 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>();
return i.template get<typename ConstructibleArrayType::value_type>();
});
}
template <typename BasicJsonType, typename CompatibleArrayType,
template <typename BasicJsonType, typename ConstructibleArrayType,
enable_if_t <
is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value and
not is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value and
not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and
not is_basic_json<CompatibleArrayType>::value,
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and
not is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and
not is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and
not is_basic_json<ConstructibleArrayType>::value,
int > = 0 >
auto from_json(const BasicJsonType& j, CompatibleArrayType& arr)
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
j.template get<typename CompatibleArrayType::value_type>(),
j.template get<typename ConstructibleArrayType::value_type>(),
void())
{
if (JSON_UNLIKELY(not j.is_array()))
......@@ -230,9 +230,9 @@ void())
from_json_array_impl(j, arr, priority_tag<3> {});
}
template<typename BasicJsonType, typename CompatibleObjectType,
enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value, int> = 0>
void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
template<typename BasicJsonType, typename ConstructibleObjectType,
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
{
if (JSON_UNLIKELY(not j.is_object()))
{
......@@ -240,13 +240,13 @@ void from_json(const BasicJsonType& j, CompatibleObjectType& obj)
}
auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
using value_type = typename CompatibleObjectType::value_type;
using value_type = typename ConstructibleObjectType::value_type;
std::transform(
inner_object->begin(), inner_object->end(),
std::inserter(obj, obj.begin()),
[](typename BasicJsonType::object_t::value_type const & p)
{
return value_type(p.first, p.second.template get<typename CompatibleObjectType::mapped_type>());
return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
});
}
......
This diff is collapsed.
......@@ -121,6 +121,28 @@ struct nocopy
j = {{"val", n.val}};
}
};
struct Data
{
std::string a;
std::string b;
};
void from_json(const json& j, Data& data)
{
j["a"].get_to(data.a);
j["b"].get_to(data.b);
}
bool operator==(Data const& lhs, Data const& rhs)
{
return lhs.a == rhs.a && lhs.b == rhs.b;
}
bool operator!=(Data const& lhs, Data const& rhs)
{
return !(lhs == rhs);
}
}
/////////////////////////////////////////////////////////////////////
......@@ -1665,4 +1687,24 @@ TEST_CASE("regression tests")
not std::is_constructible<json, std::variant<int, float>>::value, "");
}
#endif
SECTION("issue #1299 - compile error in from_json converting to container "
"with std::pair")
{
json j =
{
{"1", {{"a", "testa_1"}, {"b", "testb_1"}}},
{"2", {{"a", "testa_2"}, {"b", "testb_2"}}},
{"3", {{"a", "testa_3"}, {"b", "testb_3"}}},
};
std::map<std::string, Data> expected
{
{"1", {"testa_1", "testb_1" }},
{"2", {"testa_2", "testb_2"}},
{"3", {"testa_3", "testb_3"}},
};
const auto data = j.get<decltype(expected)>();
CHECK(expected == data);
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment