|
Boost : |
From: Andrzej Krzemienski (akrzemi1_at_[hidden])
Date: 2021-03-10 20:36:40
Hi Everyone,
Some feedback from playing with Boost.Describe for class types.
1. As others pointed out, it is confusing that BOOST_DESCRIBE_STRUCT() and
BOOST_DESCRIBE_CLASS() have such close names, but their interface and
requirements are so different. Maybe rename the latter to
BOOST_DESCRIBE_THIS_CLASS()?
2. Base class subobjects are in some applications treated equivalently to
member subobject; this is why I found it surprising that I cannot get the
names of base class subobjects. But I guess there are implementation
difficulties. Bases can be qualified names.
3. As with enums, _public_member_descriptor_fn in global namespace is UB or
invalid program as per http://eel.is/c++draft/lex.name#3.2.
4. As others pointed out, the part of the interface that uses enum
modifiers is not intuitive. I think that after a while it starts to make
sense: you decide on your use case (like doing RPC), form your enum
bitmask, and then pass it everywhere. It became more-less clear to me only
after I had a look at the implementation of member_filter:
https://github.com/pdimov/describe/blob/develop/include/boost/describe/members.hpp#L129
Maybe it makes sense to expose this in the docs.
5. Modifier mod_inherited is great for flattening the inheritance structure:
struct X {
int a;
};
struct Y : X {
int b;
};
struct Z : Y {
int c;
};
BOOST_DESCRIBE_STRUCT(X, (), (a));
BOOST_DESCRIBE_STRUCT(Y, (X), (b));
BOOST_DESCRIBE_STRUCT(Z, (Y), (c));
int main() {
namespace desc = boost::describe;
using namespace std::literals::string_literals;
constexpr auto mod = static_cast<desc::modifiers>(desc::mod_public |
desc::mod_inherited);
using L = desc::describe_members<Z, mod>;
assert((boost::mp11::mp_at_c<L, 0>::name == "a"s));
assert((boost::mp11::mp_at_c<L, 1>::name == "b"s));
assert((boost::mp11::mp_at_c<L, 2>::name == "c"s));
}
But it is not obvious at first. I recommend that the docs provide an
example like this.
It even works when base classes have members with same names:
struct X {
int a;
};
struct Y {
int a;
};
struct Z : X, Y {
int b;
};
BOOST_DESCRIBE_STRUCT(X, (), (a));
BOOST_DESCRIBE_STRUCT(Y, (), (a));
BOOST_DESCRIBE_STRUCT(Z, (X, Y), (b));
int main() {
constexpr auto mod =
static_cast<describe::modifiers>(describe::mod_public |
describe::mod_inherited);
using L = describe::describe_members<Z, mod>;
Z z = {{{3}}, {{6}}, {9}};
assert((z.*mp_at_c<L, 0>::pointer == 3));
assert((z.*mp_at_c<L, 1>::pointer == 6));
assert((z.*mp_at_c<L, 2>::pointer == 9));
}
5. What is the use case for modifier mod_hidden? I cannot think of any
situation where I would need it.
6. Regarding the overloaded functions, I am no expert in preprocessor
metaprogramming, but maybe if there was a way to provide function
signatures along the name, you would have enough information to form the
pointers. Something like:
struct X {
void f(int){}
void f(void*){}
};
BOOST_DESCRIBE_STRUCT(X, (), ( SIGNATURE(void f(int)), SIGNATURE(void
f(void*)) );
7. Modifier mod_virtual works unintuitively. It does not affect the
filtering in describe_bases<>. It is only used for decorating the list
elements. Maybe the docs should be more explicit about what it is used for.
Again, is there a use case for this?
Regards,
&rzej;
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk