Home > Back-end >  Modifying a value in a boost::json::object
Modifying a value in a boost::json::object

Time:01-08

I've been trying to use a boost::json::object to store a JSON object with several values and then modify values as needed, but have been unable to figure out a way to perform the modifications, even after reviewing information on C references and overloaded methods differing only by return type which seemed to be pertinent.

In the following test code, I create a brief JSON object in a boost::json::object as illustrated in the "Quick Look" section of the Boost.JSON documentation, read out and display a value from it, attempt to modify that value, and then read out and display the new value.

#include <iostream>
#include <boost/json/src.hpp>
#include <boost/json/object.hpp>
using std::cout;
using std::endl;

int main(int argc, char* argv[]) {

    boost::json::object testobj;

    testobj["properties"] = { { "timestamp", "Fri Jan  6 02:17:29 PM EST 2023"}, { "textDescription", "This is a Description"} };

    const boost::json::string& s = testobj.at("properties").at("textDescription").as_string();
    cout << s << endl;

    testobj.at("properties").at("textDescription").as_string() = "Hello, World!";   // ERROR

    boost::json::string t = testobj.at("properties").at("textDescription").as_string();
    cout << t << endl;
    
    return 0;
}

At the noted ERROR line, the following error is generated.

error: passing ‘const boost::json::string’ as ‘this’ argument discards qualifiers [-fpermissive]
        testobj.at("properties").at("textDescription").as_string() = "Hello, World!";
                                                                     ^~~~~~~~~~~~~~~

According to the documentation for value::as_string, there are two overloaded as_string() methods, one returning string& and the other returning string const&. Presumably, a returned string& would allow modification of the value, but I can't figure out how to access that particular overload of the method. My understanding was that if the instantiated class was const, then the const overload would be used, and otherwise the non-const overload would be used, but my instantiation is non-const and yet it's not working. Can anyone point out what I'm doing wrong here or provide some guidance on some other way to modify a value like this in a boost::json::object?

Note that I also tried getting a non-const boost::json::string& s reference and assigning a new string to it, but the compiler complained about that as well. Otherwise, everything else in the code above works as expected if the three lines preceding the return 0 line are commented out, so it's just the ERROR line that's problematic.

CodePudding user response:

Non-const value::at overloads were added in version Boost 1.80.0: https://github.com/boostorg/json/commit/95a6297480ec403ccc2cf17ff02476dc7614f60c

It fixes their issue #703:

value::at() returns value with const qualifier even if the value is non-const data.

Example

value jv1 = {{"key", 1}};
auto& a1  = jv1.as_object().at("key");  // returns value&
auto& a2  = jv1.at("key");              // returns const value&
value& a3 = jv1.at("key");              // compile error

value jv2 = {1, 2, 3};
auto& b1  = jv2.as_array().at(0);       // returns value&
auto& b2  = jv2.at(0);                  // returns const value&
value& b3 = jv2.at(0);                  // compile error

Note: value.at_pointer() has no such issue. It returns const value& if the data is const-qualified and returns value& otherwise.

Workaround for Boost 1.79.0:

This works in Boost 1.79.0:

if (auto p = testobj.if_contains("properties"))
    if (auto td = p->as_object().if_contains("textDescription"))
        td->as_string() = "Hello, World!";

Or even just

testobj["properties"].as_object()["textDescription"] = "Even better?";

See it Live On Boost 1.76.0

  • Related