Boost Json 转换错误,针对自定义对象数组

huangapple go评论70阅读模式
英文:

Boost Json conversion error for array of custom object

问题

I'm trying to code a simple json to struct (and back) conversion by using tag_invoke overload of boost::json lib.

Those are my structs:

template<class T>
void extract(boost::json::object const& obj, T& t, boost::json::string_view key)
{
    t = boost::json::value_to<T>(obj.at(key));
};

struct CRDApp {
    std::string type;
    std::string image;
    uint32_t replicas;

    friend CRDApp tag_invoke(boost::json::value_to_tag<CRDApp>, boost::json::value const& jv)
    {
        CRDApp app;
        boost::json::object const& obj = jv.as_object();
        extract(obj, app.type, "type");
        extract(obj, app.image, "image");
        extract(obj, app.replicas, "replicas");
        return app;
    }

    friend void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, CRDApp const& app)
    {
        jv = {
            { "type" , app.type },
            { "image", app.image },
            { "replicas", app.replicas }
        };
    }
};

struct CRDSpec {
    std::string _namespace;
    std::vector<CRDApp> apps;

    friend CRDSpec tag_invoke(boost::json::value_to_tag<CRDSpec>, boost::json::value const& jv)
    {
        CRDSpec spec;
        boost::json::object const& obj = jv.as_object();
        extract(obj, spec._namespace, "namespace");
        extract(obj, spec.apps, "apps");
        return spec;
    }

    friend void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, CRDSpec const& spec)
    {
        jv = {
            { "namespace" , spec._namespace },
            { "apps", spec.apps }
        };
    }
};

I've tested the json to struct conversion and is working fine, but once I've added the tag_invoke in order to convert from struct to json, the code is not compiling anymore with error:

error: no matching function for call to 'boost::json::value::value(const std::vector<CRDApp>&, std::remove_reference<boost::json::storage_ptr&&>::type)'
   35 |     return value(
      |            ^~~~~~
   36 |         *reinterpret_cast<
      |         ~~~~~~~~~~~~~~~~~~
   37 |             T const*&gt;(p),
      |             ~~~~~~~~~~~~~
   38 |         std::move(sp));
      |         ~~~~~~~~~~~~~~

If I comment out the { "apps", spec.apps } line, the code compiles again. Docs say it should automatically handle standard containers like std::vector.

Am I missing something?

英文:

I'm trying to code a simple json to struct (and back) conversion by using tag_invoke overload of boost::json lib.

Those are my structs:

template&lt;class T&gt;
void extract( boost::json::object const&amp; obj, T&amp; t, boost::json::string_view key )
{
    t = boost::json::value_to&lt;T&gt;( obj.at( key ) );
};

struct CRDApp {
    std::string type;
    std::string image;
    uint32_t replicas;

    friend CRDApp tag_invoke( boost::json::value_to_tag&lt;CRDApp&gt;, boost::json::value const&amp; jv )
    {
        CRDApp app;
        boost::json::object const&amp; obj = jv.as_object();
        extract( obj, app.type, &quot;type&quot; );
        extract( obj, app.image, &quot;image&quot; );
        extract( obj, app.replicas, &quot;replicas&quot; );
        return app;
    }

    friend void tag_invoke( boost::json::value_from_tag, boost::json::value&amp; jv, CRDApp const&amp; app )
    {
        jv = {
            { &quot;type&quot; , app.type },
            { &quot;image&quot;, app.image },
            { &quot;replicas&quot;, app.replicas }
        };
    }
};

struct CRDSpec {
    std::string _namespace;
    std::vector&lt;CRDApp&gt; apps;

    friend CRDSpec tag_invoke( boost::json::value_to_tag&lt;CRDSpec&gt;, boost::json::value const&amp; jv )
    {
        CRDSpec spec;
        boost::json::object const&amp; obj = jv.as_object();
        extract( obj, spec._namespace, &quot;namespace&quot; );
        extract( obj, spec.apps, &quot;apps&quot; );
        return spec;
    }

    friend void tag_invoke( boost::json::value_from_tag, boost::json::value&amp; jv, CRDSpec const&amp; spec )
    {   
        jv = {
            { &quot;namespace&quot; , spec._namespace },
            { &quot;apps&quot;, spec.apps }
        };
    }
};

I've tested the json to struct conversion and is working fine, but once I've added the tag_invoke in order to convert from struct to json, the code is not compiling anymore with error:

error: no matching function for call to &#39;boost::json::value::value(const std::vector&lt;CRDApp&gt;&amp;, std::remove_reference&lt;boost::json::storage_ptr&amp;&gt;::type)&#39;
   35 |     return value(
      |            ^~~~~~
   36 |         *reinterpret_cast&lt;
      |         ~~~~~~~~~~~~~~~~~~
   37 |             T const*&gt;(p),
      |             ~~~~~~~~~~~~~
   38 |         std::move(sp));
      |         ~~~~~~~~~~~~~~

If I comment out the { &quot;apps&quot;, spec.apps } line, the code compile again. Docs say it should automatically handle standard containers like std::vector.

Am I missing something?

答案1

得分: 1

以下是您提供的代码部分的翻译:

整个 tag_invoke 定制的想法 ** 是让你获得“魔法”或隐式转换。你必须调用它:

jv = {{"namespace", spec._namespace}, {"apps", boost::json::value_from(spec.apps)}};

#include <boost/json/src.hpp>
#include <iostream>

template <class T> void extract(boost::json::object const& obj, T& v, boost::json::string_view key) {
    v = boost::json::value_to<T>(obj.at(key));
};

struct CRDApp {
    std::string type;
    std::string image;
    uint32_t    replicas;

    friend CRDApp tag_invoke(boost::json::value_to_tag<CRDApp>, boost::json::value const& jv) {
        CRDApp                     app;
        boost::json::object const& obj = jv.as_object();
        extract(obj, app.type, "type");
        extract(obj, app.image, "image");
        extract(obj, app.replicas, "replicas");
        return app;
    }

    friend void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, CRDApp const& app) {
        jv = {{"type", app.type}, {"image", app.image}, {"replicas", app.replicas}};
    }

    auto operator<=>(CRDApp const&) const = default;
};

struct CRDSpec {
    std::string         _namespace;
    std::vector<CRDApp> apps;

    friend CRDSpec tag_invoke(boost::json::value_to_tag<CRDSpec>, boost::json::value const& jv) {
        CRDSpec                    spec;
        boost::json::object const& obj = jv.as_object();
        extract(obj, spec._namespace, "namespace");
        extract(obj, spec.apps, "apps");
        return spec;
    }

    friend void tag_invoke(boost::json::value_from_tag, boost::json::value& jv, CRDSpec const& spec) {
        jv = {{"namespace", spec._namespace}, {"apps", boost::json::value_from(spec.apps)}};
    }

    auto operator<=>(CRDSpec const&) const = default;
};

int main() {
    CRDSpec const spec{"some_ns",
                       {
                           {"type1", "image1", 111},
                           {"type2", "image2", 222},
                           {"type3", "image3", 333},
                           {"type4", "image4", 444},
                           {"type5", "image5", 555},
                           {"type6", "image6", 666},
                           {"type7", "image7", 777},
                           {"type8", "image8", 888},
                           {"type9", "image9", 999},
                       }};

    auto js = boost::json::value_from(spec);
    std::cout << js << "\n";

    auto roundtrip = boost::json::value_to<CRDSpec>(js);
    std::cout << "Roundtrip " << (roundtrip == spec? "equal":"different") << "\n";
}

希望这些翻译对您有所帮助。如果您需要进一步的翻译或有其他问题,请随时提问。

英文:

The whole idea of the tag_invoke customization is not that you get "magic" or implicit conversions. You have to call it:

jv = {{&quot;namespace&quot;, spec._namespace}, {&quot;apps&quot;, boost::json::value_from(spec.apps)}};

Live On Coliru

#include &lt;boost/json/src.hpp&gt;
#include &lt;iostream&gt;
template &lt;class T&gt; void extract(boost::json::object const&amp; obj, T&amp; v, boost::json::string_view key) {
v = boost::json::value_to&lt;T&gt;(obj.at(key));
};
struct CRDApp {
std::string type;
std::string image;
uint32_t    replicas;
friend CRDApp tag_invoke(boost::json::value_to_tag&lt;CRDApp&gt;, boost::json::value const&amp; jv) {
CRDApp                     app;
boost::json::object const&amp; obj = jv.as_object();
extract(obj, app.type, &quot;type&quot;);
extract(obj, app.image, &quot;image&quot;);
extract(obj, app.replicas, &quot;replicas&quot;);
return app;
}
friend void tag_invoke(boost::json::value_from_tag, boost::json::value&amp; jv, CRDApp const&amp; app) {
jv = {{&quot;type&quot;, app.type}, {&quot;image&quot;, app.image}, {&quot;replicas&quot;, app.replicas}};
}
auto operator&lt;=&gt;(CRDApp const&amp;) const = default;
};
struct CRDSpec {
std::string         _namespace;
std::vector&lt;CRDApp&gt; apps;
friend CRDSpec tag_invoke(boost::json::value_to_tag&lt;CRDSpec&gt;, boost::json::value const&amp; jv) {
CRDSpec                    spec;
boost::json::object const&amp; obj = jv.as_object();
extract(obj, spec._namespace, &quot;namespace&quot;);
extract(obj, spec.apps, &quot;apps&quot;);
return spec;
}
friend void tag_invoke(boost::json::value_from_tag, boost::json::value&amp; jv, CRDSpec const&amp; spec) {
jv = {{&quot;namespace&quot;, spec._namespace}, {&quot;apps&quot;, boost::json::value_from(spec.apps)}};
}
auto operator&lt;=&gt;(CRDSpec const&amp;) const = default;
};
int main() {
CRDSpec const spec{&quot;some_ns&quot;,
{
{&quot;type1&quot;, &quot;image1&quot;, 111},
{&quot;type2&quot;, &quot;image2&quot;, 222},
{&quot;type3&quot;, &quot;image3&quot;, 333},
{&quot;type4&quot;, &quot;image4&quot;, 444},
{&quot;type5&quot;, &quot;image5&quot;, 555},
{&quot;type6&quot;, &quot;image6&quot;, 666},
{&quot;type7&quot;, &quot;image7&quot;, 777},
{&quot;type8&quot;, &quot;image8&quot;, 888},
{&quot;type9&quot;, &quot;image9&quot;, 999},
}};
auto js = boost::json::value_from(spec);
std::cout &lt;&lt; js &lt;&lt; &quot;\n&quot;;
auto roundtrip = boost::json::value_to&lt;CRDSpec&gt;(js);
std::cout &lt;&lt; &quot;Roundtrip &quot; &lt;&lt; (roundtrip == spec? &quot;equal&quot;:&quot;different&quot;) &lt;&lt; &quot;\n&quot;;
}

Prints

{&quot;namespace&quot;:&quot;some_ns&quot;,&quot;apps&quot;:[{&quot;type&quot;:&quot;type1&quot;,&quot;image&quot;:&quot;image1&quot;,&quot;replicas&quot;:111},{&quot;type&quot;:&quot;type2&quot;,&quot;image&quot;:&quot;image2&quot;,&quot;replicas&quot;:222},{&quot;type&quot;:&quot;type3&quot;,&quot;image&quot;:&quot;image3&quot;,&quot;replicas&quot;:333},{&quot;type&quot;:&quot;type4&quot;,&quot;image&quot;:&quot;image4&quot;,&quot;replicas&quot;:444},{&quot;type&quot;:&quot;type5&quot;,&quot;image&quot;:&quot;image5&quot;,&quot;replicas&quot;:555},{&quot;type&quot;:&quot;type6&quot;,&quot;image&quot;:&quot;image6&quot;,&quot;replicas&quot;:666},{&quot;type&quot;:&quot;type7&quot;,&quot;image&quot;:&quot;image7&quot;,&quot;replicas&quot;:777},{&quot;type&quot;:&quot;type8&quot;,&quot;image&quot;:&quot;image8&quot;,&quot;replicas&quot;:888},{&quot;type&quot;:&quot;type9&quot;,&quot;image&quot;:&quot;image9&quot;,&quot;replicas&quot;:999}]}
Roundtrip equal

huangapple
  • 本文由 发表于 2023年5月31日 22:44:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76374727.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定