Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(official) example for parsing "custom data source" (implementing input iterator) does not compile #4354

Open
2 tasks done
dhebbeker opened this issue Apr 20, 2024 · 1 comment

Comments

@dhebbeker
Copy link

dhebbeker commented Apr 20, 2024

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

@dhebbeker
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants