BOOST_DEFINE_ENUM_CLASS 和 json
BOOST_DEFINE_ENUM_CLASS and json
在 the documentation for boost describe 的标题“自动转换为 JSON”下,它展示了如何实现“一个通用的 tag_invoke 重载,它自动将带注释的结构转换为 Boost.JSON 值”。该示例支持 BOOST_DESCRIBE_STRUCT,我将如何为 BOOST_DEFINE_ENUM_CLASS 实现类似的东西?
这是我天真的尝试修改示例以支持 BOOST_DEFINE_ENUM_CLASS 和 BOOST_DESCRIBE_STRUCT:
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/json.hpp>
#include <type_traits>
#include <vector>
#include <map>
namespace app {
template<class T,
class D1 = boost::describe::describe_members<T, boost::describe::mod_public | boost::describe::mod_protected>,
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
void tag_invoke(boost::json::value_from_tag const&, boost::json::value& v, T const& t) {
auto& obj = v.emplace_object();
boost::mp11::mp_for_each<D1>([&](auto D) {
obj[D.name] = boost::json::value_from(t.*D.pointer);
});
}
struct A {
int x;
int y;
};
BOOST_DESCRIBE_STRUCT(A, (), (x, y))
struct B {
std::vector<A> v;
std::map<std::string, A> m;
};
BOOST_DESCRIBE_STRUCT(B, (), (v, m))
BOOST_DEFINE_ENUM_CLASS(E1, v1, v2, v3)
struct C {
int x;
E1 e1;
};
BOOST_DESCRIBE_STRUCT(C, (), (x, e1))
} // namespace app
#include <iostream>
void main() {
app::A a{ 1, 2 };
std::cout << boost::json::value_from(a) << std::endl;
app::B b{ { { 1, 2 }, { 3, 4 } }, { { "k1", { 5, 6 } }, { "k2", { 7, 8 } } } };
std::cout << boost::json::value_from(b) << std::endl;
app::C c{ 1, app::E1::v1 };
//std::cout << boost::json::value_from(c) << std::endl;
}
我需要做什么才能为 c 启用 boost::json::value_from()?
编辑:好的,下面的代码可以解决问题,但我必须让它更模板化:
void tag_invoke(boost::json::value_from_tag const&, boost::json::value& v, E1 const& t) {
v = boost::describe::enum_to_string(t, "x");
}
文档给出了这个例子(稍作修改以适应我们 JSON 稍后的需要):
template <class E> char const* enum_to_string(E e) {
char const* r = nullptr;
boost::mp11::mp_for_each<boost::describe::describe_enumerators<E>>(
[&](auto D) {
if (e == D.value)
r = D.name;
});
return r;
}
您可以使用它来实现 value_from
自定义点:
static inline void tag_invoke(json::value_from_tag, json::value& jv, E1 e) {
auto name = enum_to_string(e);
jv = name
? name
: std::to_string(static_cast<std::underlying_type_t<E1>>(e));
}
给定合适的 SFINAE,您可以在任何枚举类型上对其进行模板化,只要您牢记将 ADL 适用性限制在您自己的枚举中以避免干扰其他库。
现场演示:
#include <boost/describe.hpp>
#include <boost/json.hpp>
#include <boost/json/src.hpp> // for online demo
#include <boost/mp11.hpp>
#include <map>
#include <type_traits>
#include <vector>
namespace app {
namespace json = boost::json;
template<class T,
class D1 = boost::describe::describe_members<T, boost::describe::mod_public | boost::describe::mod_protected>,
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
void tag_invoke(json::value_from_tag const&, json::value& v, T const& t) {
auto& obj = v.emplace_object();
boost::mp11::mp_for_each<D1>([&](auto D) {
obj[D.name] = json::value_from(t.*D.pointer);
});
}
struct A {
int x;
int y;
};
BOOST_DESCRIBE_STRUCT(A, (), (x, y))
struct B {
std::vector<A> v;
std::map<std::string, A> m;
};
BOOST_DESCRIBE_STRUCT(B, (), (v, m))
BOOST_DEFINE_ENUM_CLASS(E1, v1, v2, v3)
template <class E> char const* enum_to_string(E e) {
char const* r = nullptr;
boost::mp11::mp_for_each<boost::describe::describe_enumerators<E>>(
[&](auto D) {
if (e == D.value)
r = D.name;
});
return r;
}
static inline void tag_invoke(json::value_from_tag, json::value& jv, E1 e) {
auto name = enum_to_string(e);
jv = name
? name
: std::to_string(static_cast<std::underlying_type_t<E1>>(e));
}
struct C {
int x;
E1 e1;
};
BOOST_DESCRIBE_STRUCT(C, (), (x, e1))
} // namespace app
#include <iostream>
int main() {
app::A a{ 1, 2 };
std::cout << boost::json::value_from(a) << std::endl;
app::B b{ { { 1, 2 }, { 3, 4 } }, { { "k1", { 5, 6 } }, { "k2", { 7, 8 } } } };
std::cout << boost::json::value_from(b) << std::endl;
app::C c{ 1, app::E1::v1 };
std::cout << boost::json::value_from(c) << std::endl;
}
版画
{"x":1,"y":2}
{"v":[{"x":1,"y":2},{"x":3,"y":4}],"m":{"k1":{"x":5,"y":6},"k2":{"x":7,"y":8}}}
{"x":1,"e1":"v1"}
在 the documentation for boost describe 的标题“自动转换为 JSON”下,它展示了如何实现“一个通用的 tag_invoke 重载,它自动将带注释的结构转换为 Boost.JSON 值”。该示例支持 BOOST_DESCRIBE_STRUCT,我将如何为 BOOST_DEFINE_ENUM_CLASS 实现类似的东西?
这是我天真的尝试修改示例以支持 BOOST_DEFINE_ENUM_CLASS 和 BOOST_DESCRIBE_STRUCT:
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/json.hpp>
#include <type_traits>
#include <vector>
#include <map>
namespace app {
template<class T,
class D1 = boost::describe::describe_members<T, boost::describe::mod_public | boost::describe::mod_protected>,
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
void tag_invoke(boost::json::value_from_tag const&, boost::json::value& v, T const& t) {
auto& obj = v.emplace_object();
boost::mp11::mp_for_each<D1>([&](auto D) {
obj[D.name] = boost::json::value_from(t.*D.pointer);
});
}
struct A {
int x;
int y;
};
BOOST_DESCRIBE_STRUCT(A, (), (x, y))
struct B {
std::vector<A> v;
std::map<std::string, A> m;
};
BOOST_DESCRIBE_STRUCT(B, (), (v, m))
BOOST_DEFINE_ENUM_CLASS(E1, v1, v2, v3)
struct C {
int x;
E1 e1;
};
BOOST_DESCRIBE_STRUCT(C, (), (x, e1))
} // namespace app
#include <iostream>
void main() {
app::A a{ 1, 2 };
std::cout << boost::json::value_from(a) << std::endl;
app::B b{ { { 1, 2 }, { 3, 4 } }, { { "k1", { 5, 6 } }, { "k2", { 7, 8 } } } };
std::cout << boost::json::value_from(b) << std::endl;
app::C c{ 1, app::E1::v1 };
//std::cout << boost::json::value_from(c) << std::endl;
}
我需要做什么才能为 c 启用 boost::json::value_from()?
编辑:好的,下面的代码可以解决问题,但我必须让它更模板化:
void tag_invoke(boost::json::value_from_tag const&, boost::json::value& v, E1 const& t) {
v = boost::describe::enum_to_string(t, "x");
}
文档给出了这个例子(稍作修改以适应我们 JSON 稍后的需要):
template <class E> char const* enum_to_string(E e) {
char const* r = nullptr;
boost::mp11::mp_for_each<boost::describe::describe_enumerators<E>>(
[&](auto D) {
if (e == D.value)
r = D.name;
});
return r;
}
您可以使用它来实现 value_from
自定义点:
static inline void tag_invoke(json::value_from_tag, json::value& jv, E1 e) {
auto name = enum_to_string(e);
jv = name
? name
: std::to_string(static_cast<std::underlying_type_t<E1>>(e));
}
给定合适的 SFINAE,您可以在任何枚举类型上对其进行模板化,只要您牢记将 ADL 适用性限制在您自己的枚举中以避免干扰其他库。
现场演示:
#include <boost/describe.hpp>
#include <boost/json.hpp>
#include <boost/json/src.hpp> // for online demo
#include <boost/mp11.hpp>
#include <map>
#include <type_traits>
#include <vector>
namespace app {
namespace json = boost::json;
template<class T,
class D1 = boost::describe::describe_members<T, boost::describe::mod_public | boost::describe::mod_protected>,
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
void tag_invoke(json::value_from_tag const&, json::value& v, T const& t) {
auto& obj = v.emplace_object();
boost::mp11::mp_for_each<D1>([&](auto D) {
obj[D.name] = json::value_from(t.*D.pointer);
});
}
struct A {
int x;
int y;
};
BOOST_DESCRIBE_STRUCT(A, (), (x, y))
struct B {
std::vector<A> v;
std::map<std::string, A> m;
};
BOOST_DESCRIBE_STRUCT(B, (), (v, m))
BOOST_DEFINE_ENUM_CLASS(E1, v1, v2, v3)
template <class E> char const* enum_to_string(E e) {
char const* r = nullptr;
boost::mp11::mp_for_each<boost::describe::describe_enumerators<E>>(
[&](auto D) {
if (e == D.value)
r = D.name;
});
return r;
}
static inline void tag_invoke(json::value_from_tag, json::value& jv, E1 e) {
auto name = enum_to_string(e);
jv = name
? name
: std::to_string(static_cast<std::underlying_type_t<E1>>(e));
}
struct C {
int x;
E1 e1;
};
BOOST_DESCRIBE_STRUCT(C, (), (x, e1))
} // namespace app
#include <iostream>
int main() {
app::A a{ 1, 2 };
std::cout << boost::json::value_from(a) << std::endl;
app::B b{ { { 1, 2 }, { 3, 4 } }, { { "k1", { 5, 6 } }, { "k2", { 7, 8 } } } };
std::cout << boost::json::value_from(b) << std::endl;
app::C c{ 1, app::E1::v1 };
std::cout << boost::json::value_from(c) << std::endl;
}
版画
{"x":1,"y":2}
{"v":[{"x":1,"y":2},{"x":3,"y":4}],"m":{"k1":{"x":5,"y":6},"k2":{"x":7,"y":8}}}
{"x":1,"e1":"v1"}