mirror of
https://github.com/nlohmann/json.git
synced 2025-07-28 12:02:00 +03:00
Fix compilation of input_adapter(container) in edge cases
This fixes a compilation issue with the library if trying to use containers that don't have non-member `begin()` and `end()` functions via ADL. This patch extends the `using std::begin` and `using std::end` declarations to also cover the return type deduction of the input_adapter() template specialization for containers. The previous implementation only enabled the detection of `std::begin()` and `std::end()` in the function body, making the specialization unusable for container types that only have member `begin()` and `end()` functions. It is not typical to have `using` declarations in the namespace scope in a header file. But a C++11 implementation can't rely on fully automatic return type deduction, and needs to rely on ADL enabled helper templates. To prevent the using declarations leaking, they are enclosed in another nested namespace.
This commit is contained in:
@ -371,14 +371,35 @@ typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convenience shorthand from container to iterator
|
// Convenience shorthand from container to iterator
|
||||||
template<typename ContainerType>
|
// Enables ADL on begin(container) and end(container)
|
||||||
auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container)))
|
// Encloses the using declarations in namespace for not to leak them to outside scope
|
||||||
{
|
|
||||||
// Enable ADL
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
|
|
||||||
return input_adapter(begin(container), end(container));
|
namespace container_input_adapter_factory_impl {
|
||||||
|
|
||||||
|
using std::begin;
|
||||||
|
using std::end;
|
||||||
|
|
||||||
|
template<typename ContainerType, typename Enable = void>
|
||||||
|
struct container_input_adapter_factory {};
|
||||||
|
|
||||||
|
template<typename ContainerType>
|
||||||
|
struct container_input_adapter_factory< ContainerType,
|
||||||
|
void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))> >
|
||||||
|
{
|
||||||
|
using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
|
||||||
|
|
||||||
|
static adapter_type create(const ContainerType& container)
|
||||||
|
{
|
||||||
|
return input_adapter(begin(container), end(container));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerType>
|
||||||
|
typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
|
||||||
|
{
|
||||||
|
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special cases with fast paths
|
// Special cases with fast paths
|
||||||
|
@ -5183,14 +5183,35 @@ typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convenience shorthand from container to iterator
|
// Convenience shorthand from container to iterator
|
||||||
template<typename ContainerType>
|
// Enables ADL on begin(container) and end(container)
|
||||||
auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container)))
|
// Encloses the using declarations in namespace for not to leak them to outside scope
|
||||||
{
|
|
||||||
// Enable ADL
|
|
||||||
using std::begin;
|
|
||||||
using std::end;
|
|
||||||
|
|
||||||
return input_adapter(begin(container), end(container));
|
namespace container_input_adapter_factory_impl {
|
||||||
|
|
||||||
|
using std::begin;
|
||||||
|
using std::end;
|
||||||
|
|
||||||
|
template<typename ContainerType, typename Enable = void>
|
||||||
|
struct container_input_adapter_factory {};
|
||||||
|
|
||||||
|
template<typename ContainerType>
|
||||||
|
struct container_input_adapter_factory< ContainerType,
|
||||||
|
void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))> >
|
||||||
|
{
|
||||||
|
using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
|
||||||
|
|
||||||
|
static adapter_type create(const ContainerType& container)
|
||||||
|
{
|
||||||
|
return input_adapter(begin(container), end(container));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ContainerType>
|
||||||
|
typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
|
||||||
|
{
|
||||||
|
return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special cases with fast paths
|
// Special cases with fast paths
|
||||||
@ -16801,7 +16822,7 @@ class basic_json
|
|||||||
detail::parser_callback_t<basic_json>cb = nullptr,
|
detail::parser_callback_t<basic_json>cb = nullptr,
|
||||||
const bool allow_exceptions = true,
|
const bool allow_exceptions = true,
|
||||||
const bool ignore_comments = false
|
const bool ignore_comments = false
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
|
return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
|
||||||
std::move(cb), allow_exceptions, ignore_comments);
|
std::move(cb), allow_exceptions, ignore_comments);
|
||||||
@ -25346,7 +25367,7 @@ template<>
|
|||||||
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(
|
inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(
|
||||||
is_nothrow_move_constructible<nlohmann::json>::value&&
|
is_nothrow_move_constructible<nlohmann::json>::value&&
|
||||||
is_nothrow_move_assignable<nlohmann::json>::value
|
is_nothrow_move_assignable<nlohmann::json>::value
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
j1.swap(j2);
|
j1.swap(j2);
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ const char* end(const MyContainer& c)
|
|||||||
return c.data + strlen(c.data);
|
return c.data + strlen(c.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Custom container")
|
TEST_CASE("Custom container non-member begin/end")
|
||||||
{
|
{
|
||||||
|
|
||||||
MyContainer data{"[1,2,3,4]"};
|
MyContainer data{"[1,2,3,4]"};
|
||||||
@ -75,6 +75,31 @@ TEST_CASE("Custom container")
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Custom container member begin/end")
|
||||||
|
{
|
||||||
|
struct MyContainer2
|
||||||
|
{
|
||||||
|
const char* data;
|
||||||
|
|
||||||
|
const char* begin() const
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* end() const
|
||||||
|
{
|
||||||
|
return data + strlen(data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MyContainer2 data{"[1,2,3,4]"};
|
||||||
|
json as_json = json::parse(data);
|
||||||
|
CHECK(as_json.at(0) == 1);
|
||||||
|
CHECK(as_json.at(1) == 2);
|
||||||
|
CHECK(as_json.at(2) == 3);
|
||||||
|
CHECK(as_json.at(3) == 4);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Custom iterator")
|
TEST_CASE("Custom iterator")
|
||||||
{
|
{
|
||||||
const char* raw_data = "[1,2,3,4]";
|
const char* raw_data = "[1,2,3,4]";
|
||||||
|
Reference in New Issue
Block a user