Closed pdimov closed 3 years ago
Just to show my interest in this feature, here is a (naive) implementation of descriptor_by_name
with C++20, that requires an implementation of a compile time string such as P0259.
#include <iostream>
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include "fixed_string.hpp"
using namespace fixstr;
struct foo
{
int length;
int resistance;
};
BOOST_DESCRIBE_STRUCT(foo, (), (length, resistance))
namespace boost {
namespace describe {
template <fixed_string name>
struct by_name {
template <typename D>
struct fn {
static constexpr bool value = (name == std::string_view(D::name));
};
};
template <
typename T,
fixed_string name,
typename D = describe_members<T, mod_any_access >,
typename P = by_name<name>
>
using descriptor_by_name = mp11::mp_at<D, mp11::mp_find_if_q<D, P>>;
}
}
using namespace boost::describe;
// Annotations
template <typename T> struct annotation;
template <> struct annotation<descriptor_by_name<foo, "length">> { static constexpr auto& unit = "cm"; };
template <> struct annotation<descriptor_by_name<foo, "resistance" >> { static constexpr auto& unit = "ohm"; };
template <typename T>
void print_with_annotation(T const& x)
{
using Md = describe_members<T, mod_any_access>;
bool first = true;
boost::mp11::mp_for_each<Md>([&](auto D) {
if (!first) { std::cout << ", " << std::endl; } first = false;
std::cout << "." << D.name << " = " << x.*D.pointer << annotation<decltype(D)>::unit;
});
}
int main()
{
foo bar{ 1, 2 };
print_with_annotation(bar);
return 0;
}
I was hoping that the type of the member descriptor could be generated directly, that is without looking up the descriptor list, but that does not sound to be possible with the current approach.
Here is an implementation of descriptor_by_pointer
:
namespace boost::describe
{
namespace detail
{
template <auto pointer>
struct by_pointer
{
template <typename D, typename T1, typename T2>
struct equal { static constexpr bool value = false; };
template <typename D, typename T>
struct equal<D, T, T> { static constexpr bool value = (pointer == D::pointer); };
template <typename D>
struct fn
{
static constexpr bool value =
equal<D, std::decay_t<decltype(pointer)>, std::decay_t<decltype(D::pointer)>>::value;
};
};
} //namespace detail
template <typename Md, auto pointer, typename P = detail::by_pointer<pointer>>
using descriptor_by_pointer = mp11::mp_at<Md, mp11::mp_find_if_q<Md, P>>;
} //namespace boost::describe
I have put together a gist that shows a possible way to implement annotations with descriptor_by_pointer
(the motivating idea behind this issue) on struct members and print a data structure recursively.
Implemented.
This can be useful for "detached" annotations, as suggested by @grisumbras:
In C++14, a
descriptor_by_name
can be implemented and used like this:whereas in C++17 a
descriptor_by_pointer
can be used like this: