(official) example for parsing "custom data source" (implementing input iterator) does not compile
dhebbeker opened this issue · comments
Description
The example in the current section "Custom data source" does not compile with the current header. I don't know if the example or the library is erroneous (I suspect the former). But even if it is just an example I would expect it to compile - or to have an explanation of the necessary steps to make it work.
Current refers to the current develop
branch.
Reproduction steps
To reproduce:
- Copy the code into a source file.
- Add the missing
#include
andusing namespace
. - Optionally add dummy definition for
MyContainer::advance()
andMyContainer::get_current()
(does not make any difference at this stage) - Try to compile.
See result on Compiler Explorer with clang 15.0.0.
Expected vs. actual results
I would expect the code to compile (without linking) without errors.
Note: It compiles (not linking) if this call to the parser is used instead:
- json j = json::parse(c);
+ json j = json::parse(begin(c), end(c));
But the example is about using a container.
Minimal code example
++
#include <nlohmann/json.hpp>
using namespace nlohmann;
struct MyContainer {
void advance();
const char& get_current();
};
struct MyIterator {
using difference_type = std::ptrdiff_t;
using value_type = char;
using pointer = const char*;
using reference = const char&;
using iterator_category = std::input_iterator_tag;
MyIterator& operator++() {
target->advance();
return *this;
}
bool operator!=(const MyIterator& rhs) const {
return rhs.target != target;
}
reference operator*() const {
return target->get_current();
}
MyContainer* target = nullptr;
};
MyIterator begin(MyContainer& tgt) {
return MyIterator{&tgt};
}
MyIterator end(const MyContainer&) {
return {};
}
void foo() {
MyContainer c;
json j = json::parse(c);
}
Error messages
In file included from <source>:1:
/app/raw.githubusercontent.com/nlohmann/json/8c391e04fe4195d8be862c97f38cfe10e2a3472e/single_include/nlohmann/json.hpp:23324:16: error: no matching function for call to 'input_adapter'
parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);
^~~~~~~~~~~~~~~~~~~~~
<source>:43:20: note: in instantiation of function template specialization 'nlohmann::basic_json<>::parse<MyContainer &>' requested here
json j = json::parse(c);
^
/app/raw.githubusercontent.com/nlohmann/json/8c391e04fe4195d8be862c97f38cfe10e2a3472e/single_include/nlohmann/json.hpp:6563:27: note: candidate function not viable: no known conversion from 'MyContainer' to 'std::FILE *' (aka '_IO_FILE *') for 1st argument
inline file_input_adapter input_adapter(std::FILE* file)
^
/app/raw.githubusercontent.com/nlohmann/json/8c391e04fe4195d8be862c97f38cfe10e2a3472e/single_include/nlohmann/json.hpp:6568:29: note: candidate function not viable: no known conversion from 'MyContainer' to 'std::istream &' (aka 'basic_istream<char> &') for 1st argument
inline input_stream_adapter input_adapter(std::istream& stream)
^
/app/raw.githubusercontent.com/nlohmann/json/8c391e04fe4195d8be862c97f38cfe10e2a3472e/single_include/nlohmann/json.hpp:6573:29: note: candidate function not viable: no known conversion from 'MyContainer' to 'std::istream' (aka 'basic_istream<char>') for 1st argument
inline input_stream_adapter input_adapter(std::istream&& stream)
^
/app/raw.githubusercontent.com/nlohmann/json/8c391e04fe4195d8be862c97f38cfe10e2a3472e/single_include/nlohmann/json.hpp:6556:109: note: candidate template ignored: substitution failure [with ContainerType = MyContainer]: no type named 'adapter_type' in 'nlohmann::detail::container_input_adapter_factory_impl::container_input_adapter_factory<MyContainer>'
typename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)
~~~~~~~~~~~~ ^
/app/raw.githubusercontent.com/nlohmann/json/8c391e04fe4195d8be862c97f38cfe10e2a3472e/single_include/nlohmann/json.hpp:6589:32: note: candidate template ignored: requirement 'std::is_pointer<MyContainer>::value' was not satisfied [with CharT = MyContainer]
contiguous_bytes_input_adapter input_adapter(CharT b)
^
/app/raw.githubusercontent.com/nlohmann/json/8c391e04fe4195d8be862c97f38cfe10e2a3472e/single_include/nlohmann/json.hpp:6597:6: note: candidate template ignored: could not match 'T[N]' against 'MyContainer'
auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
^
/app/raw.githubusercontent.com/nlohmann/json/8c391e04fe4195d8be862c97f38cfe10e2a3472e/single_include/nlohmann/json.hpp:6522:69: note: candidate function template not viable: requires 2 arguments, but 1 was provided
typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
^
1 error generated.
Compiler returned: 1
Compiler and operating system
x86-64 clang 15.0.0
Library version
Validation
- The bug also occurs if the latest version from the
develop
branch is used. - I can successfully compile and run the unit tests.
I think the issue is here:
void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>
This does not allow begin()
and end()
to require lvalue references.
In the example those functions require lvalue references (begin(MyContainer& tgt)
). This should be legitimate as std::begin()
also expects lvalue references for container types. But std::declval()
returns an rvalue reference by definition.