Search code examples
c++boostboost-json

How to construct boost::json value?


I have the following code for constructing Boost::Json value object.

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AppointmentEnd const& obj)
{
    jv = { { "MridianPatientOid", obj.mridianPatientOid }, { "PdfOids", obj.pdfOids } };
}

It works perfectly fine with Boost version 1.79.

I'm trying to upgrade the Boost version 1.86, but it gives me the following error:

C:\Users\bobef\.conan2\p\b\boost8a406c6ccf4da\p\include\boost\json\impl\value_ref.hpp(36): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'boost::json::value'

...

C:\projects\work\mercury\libs\ois-data\code\ois-data\models\states\AppointmentEnd.cpp(16): note: see reference to function template instantiation 'boost::json::value_ref::value_ref<std::vector<std::string,std::allocator<std::string>>>(const T &,void *) noexcept' being compiled
          with
          [
              T=std::vector<std::string,std::allocator<std::string>>
          ]

C:\Users\bobef\.conan2\p\b\boost8a406c6ccf4da\p\include\boost/json/value_ref.hpp(204): note: see reference to function template instantiation 'boost::json::value boost::json::value_ref::from_const<std::vector<std::string,std::allocator<std::string>>>(const void *,boost::json::storage_ptr)' being compiled
  ninja: build stopped: subcommand failed.

I can use the following workaround but it is lengthy and ugly.

void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AppointmentEnd const& obj)
{
  boost::json::object obj_;
  obj_["MridianPatientOid"] = obj.mridianPatientOid;
  obj_["PdfOids"] = array(obj.pdfOids.begin(), obj.pdfOids.end());
  jv = obj_;
}

The compiler version I'm using is Microsoft Visual Studio Community 2022 (64-bit) Version 17.11.2.

Could someone explain the source of the error and propose a more compact workaround?


Solution

  • Your initializer includes obj.pdfOids as a value. Likely that's a container, and as such is not implicitely convertible to a json::value. Instead, use value_from again:

    Live On Coliru

    #include <boost/json.hpp>
    #include <iostream>
    namespace json = boost::json;
    
    struct AppointmentEnd {
        std::string              mridianPatientOid;
        std::vector<std::string> pdfOids;
    
      private:
        friend void tag_invoke(json::value_from_tag, json::value& jv, AppointmentEnd const& obj) {
            jv = {
                {"MridianPatientOid", obj.mridianPatientOid},
                {"PdfOids", json::value_from(obj.pdfOids)},
            };
        }
    };
    
    int main() {
        std::cout << json::value_from(AppointmentEnd{ "ABC", {"pdfOid1", "pdfOid2"} });
    }
    

    Printing

    {"MridianPatientOid":"ABC","PdfOids":["pdfOid1","pdfOid2"]}