You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is a sort-of continuation, sort-of reopening of #3130 - it's not exactly the same use case, but certain applications of items() on a json object still don't play nicely with C++20 std::ranges.
In particular, while items() can be used as an input for views like std::views::transform, that result isn't usable in situations that require a forward_iterator, such as constructing a container from the output range's iterators. See the code below for what I mean.
The compilation error suggests the view iterator's iterator_category is not defined, which is the case if the base range doesn't model forward_range.
I did some debugging using static_asserts, and found that while iteration_proxy_valuedoes meet all the requirements for a forward_iterator, its iterator_category is explicitly exposed as only std::input_iterator_tag. Simply changing that to std::forward_iterator_tag (or removing it and letting iterator_traits deduce it) in my testing makes it fully model forward_iterator, so that items() models forward_range and the view is usable in this case.
Reproduction steps
Crate a json object
Run its items() through an std::views::transform
Try to construct a container via that result's iterators, e.g. std::vector<std::string> s{view.begin(), view.end()};
Expected vs. actual results
iteration_proxy is just a wrapper around the actual iterator of json itself, which does satisfy forward_iterator, so I expect iteration_proxy_value to also satisfy forward_iterator. Instead, it only satisfies input_iterator.
Minimal code example
#include<nlohmann/json.hpp>
#include<ranges>
#include<string>
#include<vector>intmain()
{
// This works
nlohmann::json arr { 1, 2, 3 };
auto arrTransform = std::views::transform([](auto&& element){ return element.templateget<int>() * 2; });
auto arrView = arr | arrTransform;
std::vector<int> arrVec{arrView.begin(), arrView.end()};
// This doesn't work
nlohmann::json obj {
{ "one", 1 },
{ "two", 2 },
{ "three", 3 }
};
auto objItems = obj.items();
auto objTransform = std::views::transform([](auto&& element){ return element.key(); });
auto objView = objItems | objTransform;
std::vector<std::string> keys{objView.begin(), objView.end()}; // Fails to compile
}
Error messages
json-range.cpp: In function ‘int main()’:
json-range.cpp:24:65: error: no matching function for call to ‘std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > >::vector(<brace-enclosed initializer list>)’
23 | std::vector<std::string> keys{objView.begin(), objView.end()}; // Fails to compile
| ^
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/vector:66,
from /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/functional:64,
from /usr/include/nlohmann/json.hpp:23,
from json-range.cpp:1:
/usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/stl_vector.h:707:9: note: candidate: ‘template<class _InputIterator, class> constexpr std::vector<_Tp, _Alloc>::vector(_InputIterator, _InputIterator, const allocator_type&) [with <template-parameter-2-2> = _InputIterator; _Tp = std::__cxx11::basic_string<char>; _Alloc = std::allocator<std::__cxx11::basic_string<char> >]’
707 | vector(_InputIterator __first, _InputIterator __last,
| ^~~~~~
/usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/stl_vector.h:707:9: note: template argument deduction/substitution failed:
In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/stl_algobase.h:65,
from /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/algorithm:60,
from /usr/include/nlohmann/json.hpp:21:
/usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/stl_iterator_base_types.h: In substitution of ‘template<class _InIter> using std::_RequireInputIter = std::__enable_if_t<std::is_convertible<typename std::iterator_traits< <template-parameter-1-1> >::iterator_category, std::input_iterator_tag>::value> [with _InIter = std::ranges::transform_view<std::ranges::ref_view<nlohmann::json_abi_v3_11_3::detail::iteration_proxy<nlohmann::json_abi_v3_11_3::detail::iter_impl<nlohmann::json_abi_v3_11_3::basic_json<> > > >, main()::<lambda(auto:24&&)> >::_Iterator<false>]’:
/usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/stl_vector.h:705:9: required from here
/usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/stl_iterator_base_types.h:250:11: error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<std::ranges::transform_view<std::ranges::ref_view<nlohmann::json_abi_v3_11_3::detail::iteration_proxy<nlohmann::json_abi_v3_11_3::detail::iter_impl<nlohmann::json_abi_v3_11_3::basic_json<> > > >, main()::<lambda(auto:24&&)> >::_Iterator<false> >’
250 | using _RequireInputIter =
| ^~~~~~~~~~~~~~~~~
Compiler and operating system
Gentoo, GCC 13.2
Library version
3.11.3
Validation
The bug also occurs if the latest version from the develop branch is used.
Description
This is a sort-of continuation, sort-of reopening of #3130 - it's not exactly the same use case, but certain applications of
items()
on a json object still don't play nicely with C++20std::ranges
.In particular, while
items()
can be used as an input for views likestd::views::transform
, that result isn't usable in situations that require aforward_iterator
, such as constructing a container from the output range's iterators. See the code below for what I mean.The compilation error suggests the view iterator's
iterator_category
is not defined, which is the case if the base range doesn't modelforward_range
.I did some debugging using
static_assert
s, and found that whileiteration_proxy_value
does meet all the requirements for aforward_iterator
, itsiterator_category
is explicitly exposed as onlystd::input_iterator_tag
. Simply changing that tostd::forward_iterator_tag
(or removing it and lettingiterator_traits
deduce it) in my testing makes it fully modelforward_iterator
, so thatitems()
modelsforward_range
and the view is usable in this case.Reproduction steps
json
objectitems()
through anstd::views::transform
std::vector<std::string> s{view.begin(), view.end()};
Expected vs. actual results
iteration_proxy
is just a wrapper around the actual iterator ofjson
itself, which does satisfyforward_iterator
, so I expectiteration_proxy_value
to also satisfyforward_iterator
. Instead, it only satisfiesinput_iterator
.Minimal code example
Error messages
Compiler and operating system
Gentoo, GCC 13.2
Library version
3.11.3
Validation
develop
branch is used.The text was updated successfully, but these errors were encountered: