Fix compilation of input_adapter(container) in edge cases
This fixes a compilation issue with the library if trying to parse JSON from a
custom container type that doesn't support detecting `begin()` and `end()`
functions via ADL.
`include/nlohmann/detail/input/input_adapters.hpp` defines convenience function
for creating input adapter for STL-like containers. It should support iterators
both via `std::begin()` and `std::end()`, as well as `begin()` and `end()` found
via ADL. However, the former doesn't actually work for iterable types not
defined in the `std` namespace, due to the way the return type deduction is
implemented:
$ cat test.cc
#include <iostream>
#include <nlohmann/json.hpp>
const char DATA[] = R"("Hello, world!")";
struct MyIterable {
using iterator = const char*;
using const_iterator = iterator;
const_iterator begin() const { return DATA; }
const_iterator end() const { return DATA + sizeof(DATA); }
};
int main()
{
const auto c = MyIterable {};
std::cout << nlohmann::json::parse(c) << "\n";
return 0;
}
$ g++ --version
g++ (Ubuntu 10.2.0-13ubuntu1) 10.2.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ -std=c++11 test.cc
...
/usr/include/nlohmann/detail/input/input_adapters.hpp:375:6: note: candidate: ‘template<class ContainerType> decltype (nlohmann::detail::input_adapter(begin(container), end(container))) nlohmann::detail::input_adapter(const ContainerType&)’
375 | auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container)))
| ^~~~~~~~~~~~~
/usr/include/nlohmann/detail/input/input_adapters.hpp:375:6: note: template argument deduction/substitution failed:
/usr/include/nlohmann/detail/input/input_adapters.hpp: In substitution of ‘template<class ContainerType> decltype (nlohmann::detail::input_adapter(begin(container), end(container))) nlohmann::detail::input_adapter(const ContainerType&) [with ContainerType = MyIterable]’:
...
In the above example the trailing type deduction won't look for the `begin()`
and `end()` functions in the `std` namespace, although the function body would.
I don't know about a more elegant fix in C++11 except to spell out the return
type verbatim.
This commit is contained in:
parent
f78d456075
commit
1c130315ac
@ -372,7 +372,7 @@ 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>
|
template<typename ContainerType>
|
||||||
auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container)))
|
typename iterator_input_adapter_factory<typename ContainerType::const_iterator>::adapter_type input_adapter(const ContainerType& container)
|
||||||
{
|
{
|
||||||
// Enable ADL
|
// Enable ADL
|
||||||
using std::begin;
|
using std::begin;
|
||||||
|
|||||||
@ -5179,7 +5179,7 @@ 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>
|
template<typename ContainerType>
|
||||||
auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container)))
|
typename iterator_input_adapter_factory<typename ContainerType::const_iterator>::adapter_type input_adapter(const ContainerType& container)
|
||||||
{
|
{
|
||||||
// Enable ADL
|
// Enable ADL
|
||||||
using std::begin;
|
using std::begin;
|
||||||
@ -16793,7 +16793,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);
|
||||||
@ -25338,7 +25338,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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,6 +50,8 @@ TEST_CASE("Use arbitrary stdlib container")
|
|||||||
|
|
||||||
struct MyContainer
|
struct MyContainer
|
||||||
{
|
{
|
||||||
|
using iterator = const char*;
|
||||||
|
using const_iterator = iterator;
|
||||||
const char* data;
|
const char* data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user