From 1c130315acacc5a809febf0e387917bf6e21acc7 Mon Sep 17 00:00:00 2001 From: Jaakko Moisio Date: Fri, 25 Dec 2020 14:26:25 +0100 Subject: [PATCH] Fix compilation of input_adapter(container) in edge cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 #include 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 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 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. --- include/nlohmann/detail/input/input_adapters.hpp | 2 +- single_include/nlohmann/json.hpp | 6 +++--- test/src/unit-user_defined_input.cpp | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 63921ca55..6c6f56d1e 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -372,7 +372,7 @@ typename iterator_input_adapter_factory::adapter_type input_adapte // Convenience shorthand from container to iterator template -auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container))) +typename iterator_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) { // Enable ADL using std::begin; diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 9e6f6012d..e5f415670 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5179,7 +5179,7 @@ typename iterator_input_adapter_factory::adapter_type input_adapte // Convenience shorthand from container to iterator template -auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container))) +typename iterator_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) { // Enable ADL using std::begin; @@ -16793,7 +16793,7 @@ class basic_json detail::parser_callback_tcb = nullptr, const bool allow_exceptions = true, const bool ignore_comments = false - ) + ) { return ::nlohmann::detail::parser(std::move(adapter), std::move(cb), allow_exceptions, ignore_comments); @@ -25338,7 +25338,7 @@ template<> inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( is_nothrow_move_constructible::value&& is_nothrow_move_assignable::value - ) +) { j1.swap(j2); } diff --git a/test/src/unit-user_defined_input.cpp b/test/src/unit-user_defined_input.cpp index 5a1138b00..507f7206e 100644 --- a/test/src/unit-user_defined_input.cpp +++ b/test/src/unit-user_defined_input.cpp @@ -50,6 +50,8 @@ TEST_CASE("Use arbitrary stdlib container") struct MyContainer { + using iterator = const char*; + using const_iterator = iterator; const char* data; };