If your pointers are to user-defined types, you can "just" overload for the pointer:
template <class T>
void tag_invoke(boost::json::value_from_tag const&, boost::json::value& v, T const* p) {
if (p)
boost::json::value_from(*p, v);
else
v.emplace_null();
}
This works because of ADL:
Live On Coliru
#include <boost/describe.hpp>
#include <boost/json/src.hpp>
#include <boost/mp11.hpp>
#include <iostream>
namespace app {
struct MyInt {
int value;
};
template <class T>
void tag_invoke(boost::json::value_from_tag const&, boost::json::value& v, T const* p) {
if (p)
boost::json::value_from(*p, v);
else
v.emplace_null();
}
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); });
}
MyInt b{42};
struct A {
MyInt* i;
};
BOOST_DESCRIBE_STRUCT(MyInt, (), (value))
BOOST_DESCRIBE_STRUCT(A, (), (i))
A a{&b};
} // namespace app
int main() {
std::cout << boost::json::value_from(app::a) << std::endl;
}
Printing
{"i":{"value":42}}
Primitive Types
However your type is not user-defined. Primitive types like int
do not have any associated namespace. The above doesn't work...
You would either have to explicitly include the overload, which requires modifying library code, or you can make the pointer-handling explicit in your code:
boost::mp11::mp_for_each<D1>([&](auto D) {
auto&& v = t.*D.pointer;
if constexpr (std::is_pointer_v<std::remove_cvref_t<decltype(v)>>) {
obj[D.name] = boost::json::value_from(*v);
} else {
obj[D.name] = boost::json::value_from(v);
}
});
This will work. Live On Coliru
#include <boost/describe.hpp>
#include <boost/json/src.hpp>
#include <boost/mp11.hpp>
#include <iostream>
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) {
auto&& v = t.*D.pointer;
if constexpr (std::is_pointer_v<std::remove_cvref_t<decltype(v)>>) {
obj[D.name] = boost::json::value_from(*v);
} else {
obj[D.name] = boost::json::value_from(v);
}
});
}
int b{42};
struct A {
int* i;
};
BOOST_DESCRIBE_STRUCT(A, (), (i))
A a{&b};
} // namespace app
int main() {
std::cout << boost::json::value_from(app::a) << std::endl;
}
Printing
{"i":42}
Notes
Note that raw pointers are problematic at best. It will be completely unclear what to do when deserializing instead. I suspect you might want to look at Boost Serialization instead if you need that kind of support.