I want to test whether a path exists in a json file. For example, "_/root/settings/logging_".
auto jPtr = json::json_pointer("/root/settings/logging"_json_pointer);
auto exists1 = jsonfile.contains(jPtr);
auto exists2 = jsonfile.contains(json::json_pointer("/root/settings/logging"_json_pointer));
exists1 is false and exists2 is true.
I expected both of these to be true. Is this a bug or is this expected behaviour?
UPDATE: There are two contains functions. One which takes an rvalue reference to a KeyT and one which takes a reference to a json_pointer. Both do different things. This seems inconsistent to me. If I std::move jPtr it works but I don't want to move the pointer.
g++ (Ubuntu 8.3.0-6ubuntu1~18.10.1) 8.3.0
v3.7.0
auto jPtr = json::json_pointer("/root/settings/logging"_json_pointer);
There is maybe one _json_pointer too much here?
Isn't it either
auto jPtr = json::json_pointer("/root/settings/logging");
or
auto jPtr = "/root/settings/logging"_json_pointer;
What do you see when printing your jPtr?
Thanks for replying but I've tested your suggestions and neither of them work.
at seems to behave correctly. I haven't tested it fully yet but the code below works (outputsExists). I'd want to use contains as it doesn't throw an exception.
try
{
json::json_pointer p {"/root/settings/logging"};
jsonfile.at(p);
std::cout << "Exists" << std::endl;
}
catch (const json::exception &e)
{
std::cout << "Doesn't exist" << std::endl;
}
Also, is there any way to enumerate all key value pairs in a json file? The items() doesn't return all keys/values.
Indeed there is a double invocation of the JSON Pointer constructor if you call
json::json_pointer("/root/settings/logging"_json_pointer)
For your example, this code works:
#include "json.hpp"
#include <iostream>
using json = nlohmann::json;
int main()
{
json j;
j["root"]["settings"]["logging"] = true;
std::cout << std::boolalpha
<< j.contains("/root/settings/logging"_json_pointer) << '\n'
<< j.contains("/no/value/here"_json_pointer)
<< std::endl;
}
Output:
true
false
Thanks but my question was about passing an instance of json::json_pointer and not hard coded paths.
It is related to the contains function and it's different implementations for const and non-const json_pointers.
auto jptr1= "/root/settings/logging"_json_pointer;
auto jptr2= json::json_pointer{"/root/settings/logging"};
std::cout << std::boolalpha << j.contains(jptr1);
std::cout << std::boolalpha << j.contains(jptr2);
....both return false. But if I make them both const, they return true!
const auto jptr1= "/root/settings/logging"_json_pointer;
const auto jptr2= json::json_pointer{"/root/settings/logging"};
std::cout << std::boolalpha << j.contains(jptr1);
std::cout << std::boolalpha << j.contains(jptr2);
Is this a bug because this really caught me out.
I see.
Calling contains with a non-const json_pointer calls
template<typename KeyT, typename std::enable_if<
not std::is_same<KeyT, json_pointer>::value, int>::type = 0>
bool contains(KeyT && key) const
{
return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();
}
which is wrong, whereas calling it with a const json_pointer calls
bool contains(const json_pointer& ptr) const
{
return ptr.contains(this);
}
which is correct.
I am puzzled. Any ideas?
I'm not familiar enough with the codebase to suggest a proper fix but I've added a contains function which accepts a non const json_pointer and this works.
bool contains(json_pointer& ptr) const
{
return ptr.contains(this);
}
Could you explain to me what the std::enable_if is mean't to achieve? Is it to prevent calls passing a json_pointer parameter because it does not do this. Is this a bug?
template<typename KeyT, typename std::enable_if<
not std::is_same<KeyT, json_pointer>::value, int>::type = 0>
bool contains(KeyT && key) const
{
return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();
}
Hey @devhandle I have explained why this wasn't working in the pull requests but if you need more explanation from my side, don't doubt into dropping me a message :)
Thanks @tete17!
I've tested your change and it fixes my issue. Also, thanks for the explanation - much appreciated.