In the documentation of Boost Describe, there is an example for automatic conversion of a struct to JSON. However, when adding an enum (not a nested one) as a member of the struct, the code example does not work. I guess that the tag_invoke
function needs to be modified in order to handle the enum.
I tried the following, based on the example:
#include <boost/describe.hpp>
#include <boost/json.hpp>
#include <boost/mp11.hpp>
#include <iostream>
#include <map>
#include <type_traits>
#include <vector>
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 &&
!std::is_union<T>::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); });
}
enum E { e1, e2 };
BOOST_DESCRIBE_ENUM(E, e1, e2);
struct A {
int x;
int y;
E e;
};
BOOST_DESCRIBE_STRUCT(A, (), (x, y, e))
} // namespace app
int main() {
app::A a{1, 2, app::e1};
std::cout << boost::json::value_from(a) << std::endl;
}
CodePudding user response:
You only have the tag_invoke
defined for class types.
You need to add one for enumeration types:
template <
class E,
class = std::enable_if_t<boost::describe::has_describe_enumerators<E>::value>>
void tag_invoke(boost::json::value_from_tag const&, boost::json::value& v, E const& e) {
auto s = boost::describe::enum_to_string(e, 0);
v = s ? s : std::to_string(static_cast<std::underlying_type_t<E>>(e));
}
Now your sample works:
#include <boost/core/demangle.hpp>
#include <boost/describe.hpp>
#include <boost/json/src.hpp>
#include <boost/mp11.hpp>
#include <iostream>
namespace app {
template <
class E,
class = std::enable_if_t<boost::describe::has_describe_enumerators<E>::value>>
void tag_invoke(boost::json::value_from_tag const&, boost::json::value& v, E const& e) {
auto s = boost::describe::enum_to_string(e, 0);
v = s ? s : std::to_string(static_cast<std::underlying_type_t<E>>(e));
}
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 &&
!std::is_union<T>::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); });
}
enum E { e1, e2 };
struct A {
int x;
int y;
E e;
};
BOOST_DESCRIBE_ENUM(E, e1, e2)
BOOST_DESCRIBE_STRUCT(A, (), (x, y, e))
} // namespace app
int main() {
app::A a{1, 2, app::e1};
std::cout << boost::json::value_from(a) << std::endl;
}
Prints
{"x":1,"y":2,"e":"e1"}