#include #include class visitor_adaptor_with_metadata { public: template void visit(const Fnc& fnc) const; int metadata = 42; private: template void do_visit(const Ptr& ptr, const Fnc& fnc) const; }; using json = nlohmann::basic_json < std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, nlohmann::adl_serializer, std::vector, visitor_adaptor_with_metadata >; template void visitor_adaptor_with_metadata::visit(const Fnc& fnc) const { do_visit(json::json_pointer{}, fnc); } template void visitor_adaptor_with_metadata::do_visit(const Ptr& ptr, const Fnc& fnc) const { using value_t = nlohmann::detail::value_t; const json& j = *static_cast(this); switch (j.type()) { case value_t::object: fnc(ptr, j); for (const auto& entry : j.items()) { entry.value().do_visit(ptr / entry.key(), fnc); } break; case value_t::array: fnc(ptr, j); for (std::size_t i = 0; i < j.size(); ++i) { j.at(i).do_visit(ptr / std::to_string(i), fnc); } break; case value_t::null: case value_t::string: case value_t::boolean: case value_t::number_integer: case value_t::number_unsigned: case value_t::number_float: case value_t::binary: fnc(ptr, j); break; case value_t::discarded: default: break; } } int main() { // create a json object json j; j["null"]; j["object"]["uint"] = 1U; j["object"].metadata = 21; // visit and output j.visit( [&](const json::json_pointer & p, const json & j) { std::cout << (p.empty() ? std::string{"/"} : p.to_string()) << " - metadata = " << j.metadata << " -> " << j.dump() << '\n'; }); }