Rapidjson: Support C++11 range-based loop

Created on 17 Oct 2014  ·  10Comments  ·  Source: Tencent/rapidjson

Currently the for(auto item& : myValue) loop is not supported by rapidjson. I guess this is because the case of Begin and End does not match what the standard expects.

I'd like to use this for array iteration, though I suspect it could also be useful over members as well.

enhancement

Most helpful comment

Two things to note here:

  • You can use GetArray()/GetObject() functions to use range-based for over arrays or objects:
  • As RapidJSON value are generally not copyable, you should loop over references instead
  Document doc;
  // ... fill the array
  for( const auto& e : doc.GetArray() ) // loop over array
     std::cout << e.GetInt() << std::endl;

  // ... fill an object
  for( auto& m : doc.GetObject() ) // loop over object (non-const)
    m.value.SetNull(); // modify entry 

All 10 comments

This can be achieved by simply adding the following four functions to the rapidjson namespace:

namespace rapidjson {
template <typename Encoding, typename Allocator>
typename GenericValue<Encoding,Allocator>::ValueIterator begin(GenericValue<Encoding,Allocator>& v) { return v.Begin(); }
template <typename Encoding, typename Allocator>
typename GenericValue<Encoding,Allocator>::ConstValueIterator begin(const GenericValue<Encoding,Allocator>& v) { return v.Begin(); }

template <typename Encoding, typename Allocator>
typename GenericValue<Encoding,Allocator>::ValueIterator end(GenericValue<Encoding,Allocator>& v) { return v.End(); }
template <typename Encoding, typename Allocator>
typename GenericValue<Encoding,Allocator>::ConstValueIterator end(const GenericValue<Encoding,Allocator>& v) { return v.End(); }
} // namespace rapidjson

I'm not sure, if adding this to the core library is sufficient, though. GenericValue is a variant type, which should at least allow you to select the "iteration type" you want to use: array element vs. object members.

Thanks @pah, this is great.

Would there be any overhead of confusion from the following new API?

for (auto& item : doc.ArrayItems()) {}
for (auto& member : doc.Members()) {}

Yes, something like this could be an option.

I thought of shallow wrapper objects returned by functions GetArray()/ GetObject() (symmetric to GetInt, etc.), restricting access to a GenericValue to the specific type and adding additional convenience APIs like range-loop support.

boost::make_iterator_range(doc.Begin(), doc.End())
boost::make_iterator_range(doc.MemberBegin(), doc.MemberEnd())

So that you can do it even with free functions.

+1

+1

@pah Your idea of GetArray()/GetObject has been implemented in PR #542 .
Please review the PR when you have time. Thank you.

Merged #542

As mentioned in the first post, the capitalization of B and E on Begin() and End() functions are preventing auto ranged based for looping. for (auto Val : Doc).

I've attempted to change them to lowercase myself however at that point the compiler starts telling you you're trying to access private/protected member functions when you shouldn't be..

Two things to note here:

  • You can use GetArray()/GetObject() functions to use range-based for over arrays or objects:
  • As RapidJSON value are generally not copyable, you should loop over references instead
  Document doc;
  // ... fill the array
  for( const auto& e : doc.GetArray() ) // loop over array
     std::cout << e.GetInt() << std::endl;

  // ... fill an object
  for( auto& m : doc.GetObject() ) // loop over object (non-const)
    m.value.SetNull(); // modify entry 
Was this page helpful?
0 / 5 - 0 ratings