nlohmann / json

JSON for Modern C++

Home Page:https://json.nlohmann.me

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

(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:

  1. Copy the code into a source file.
  2. Add the missing #include and using namespace.
  3. Optionally add dummy definition for MyContainer::advance() and MyContainer::get_current() (does not make any difference at this stage)
  4. 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

8c391e0

Validation

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.