首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >描述第三方类型

描述第三方类型
EN

Stack Overflow用户
提问于 2022-04-28 01:20:17
回答 1查看 54关注 0票数 1

我使用boost::json库来生成json字符串,但是对于第三方类型,BOOST_DESCRIBE_CLASS无法理解。我可以使用朋友函数的类,使用第三方风格,但这是太多。有什么办法只处理一次,到处使用吗?示例:

代码语言:javascript
复制
class CTest
{
public:
    Imath::V3d v;

    BOOST_DESCRIBE_CLASS(CTest, (), (v), (), ())
};
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-28 02:58:36

我不得不猜测,所以我开始着手处理一个泛型转换函数。

您确实会使用tag_invoke

代码语言:javascript
复制
namespace bd = boost::describe;

template <class T, //
          class Bd = bd::describe_bases<T, bd::mod_any_access>,
          class Md = bd::describe_members<T, bd::mod_any_access>,
          class En = std::enable_if_t<!std::is_union<T>::value>>
void tag_invoke(json::value_from_tag, json::value& v, T const& obj) {
    json::object bases, members;

    boost::mp11::mp_for_each<Bd>([&, first = true](auto const& D) mutable {
        using B = typename std::decay_t<decltype(D)>::type;
        bases.emplace(boost::core::demangle(typeid(B).name()),
                      json::value_from(static_cast<B const&>(obj)));
    });

    boost::mp11::mp_for_each<Md>([&](auto D) {
        members.emplace(D.name, json::value_from(obj.*D.pointer));
    });

    json::object result;
    if (bases.size())
        result.emplace("bases", std::move(bases));
    if (members.size())
        result.emplace("members", std::move(members));

    v = std::move(result);
}

这里是演示中的:

住在Coliru

代码语言:javascript
复制
class CTest
{
public:
    int v = 42;
    BOOST_DESCRIBE_CLASS(CTest, (), (v), (), ())
};

struct X { int m1 = 1; };
struct Y { int m2 = 2; };
BOOST_DESCRIBE_STRUCT(X, (), (m1))
BOOST_DESCRIBE_STRUCT(Y, (), (m2))

class Z : public X , public Y {
    int m1 = 3, m2 = 4;
    BOOST_DESCRIBE_CLASS(Z, (X, Y), (), (), (m1, m2))
};

int main() 
{
    std::cout << json::value_from(CTest{}) << "\n";
    std::cout << json::value_from(Z{}) << "\n";
}

打印

代码语言:javascript
复制
{"members":{"v":42}}
{"bases":{"X":{"members":{"m1":1}},"Y":{"members":{"m2":2}}},"members":{"m1":3,"m2":4}}

第三方类型

第三方类型也可以以同样的方式进行转换。让我们想象一下,第三方标题包含如下内容:

代码语言:javascript
复制
namespace Imath {
    struct V3d {
        std::tuple<float, float, float> coords;
        std::string meta;
    };
};

你不能编辑标题。但是,您可以在您自己的文件中添加以下内容:

代码语言:javascript
复制
namespace boost::json {
    void tag_invoke(json::value_from_tag, json::value& v,
                    Imath::V3d const& v3d) {
        v = json::object{
            {"x", std::get<0>(v3d.coords)},
            {"y", std::get<1>(v3d.coords)},
            {"z", std::get<2>(v3d.coords)},
            {"meta", v3d.meta},
        };
    }
} // namespace json

对于ADL,也可以将tag_invoke重载放入Imath命名空间(或者更确切地说,是声明V3d的名称空间),但是您可能更喜欢boost::json名称空间,因为它特别希望这个定制点的重载。

现在输出变成:

住在Coliru

代码语言:javascript
复制
class CTest
{
  public:
    Imath::V3d v{{11, 22, 33}, "This is very nifty"};
    BOOST_DESCRIBE_CLASS(CTest, (), (v), (), ())
};

struct X { int m1 = 1; };
struct Y { int m2 = 2; };
BOOST_DESCRIBE_STRUCT(X, (), (m1))
BOOST_DESCRIBE_STRUCT(Y, (), (m2))

class Z : public X , public Y {
    int m1 = 3, m2 = 4;
    BOOST_DESCRIBE_CLASS(Z, (X, Y), (), (), (m1, m2))
};

int main() 
{
    std::cout << json::value_from(CTest{}) << "\n";
    std::cout << json::value_from(Z{}) << "\n";
}

印刷:

代码语言:javascript
复制
{"members":{"v":{"x":1.1E1,"y":2.2E1,"z":3.3E1,"meta":"This is very nifty"}}}
{"bases":{"X":{"members":{"m1":1}},"Y":{"members":{"m2":2}}},"members":{"m1":3,"m2":4}}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72036938

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档