Closed ccvca closed 4 years ago
Hello,
Yes, that is entirely doable through a combination of an attribute of a variadic template type and refl::util::for_each
. There is no built-in way in C++ to get that information, so someone will have to provide it manually (proposal for it seems to have been rejected https://stackoverflow.com/a/33664204).
Currently there is a bug in the built-in refl::attr::base_types
, so I would recommend not using it. I expect that it will end up being replaced by something more useful.
Instead, you could create your own attribute like so:
template <typename... Ts>
struct Bases : public refl::attr::usage::type {
static constexpr refl::type_list<refl::type_descriptor<Ts>...> descriptors;
};
And use it like this:
constexpr auto bases = refl::descriptor::get_attribute<Bases>(refl::reflect<T>());
if constexpr (bases.descriptors.size) {
for_each(bases.descriptors, [](auto t) {
std::cout << t.name << '\n';
});
}
"get_attribute" does not accept a template type like BaseClass
get_attribute
has an overload that accepts a variadic Attribute<Ts...>
as well. It is not available unprefixed (like for_each
) since ADL does not kick-in for names with explicitly specified types.
If there is a ForEach for attributes
for_each
iterates over type_list<Ts...>
only, but one could use refl::trait::as_type_list_t
to convert any T<Ts..>
(like std::tuple<Ts...>
) into type_list<Ts...>
.
PS: You've build a great library.
Thanks.
Many thanks, this library is more powerful than I expected :).
If anyone needs something similar, here is a complete example: (Tested using v0.8.1)
#include <iostream>
#include <refl.hpp>
#include <string>
template <typename... Ts>
struct Bases : public refl::attr::usage::type {
static constexpr refl::type_list<refl::type_descriptor<Ts>...> descriptors = {};
};
struct Base1_t{
std::string Base1A;
std::string Base1B;
};
REFL_TYPE(Base1_t)
REFL_FIELD(Base1A)
REFL_FIELD(Base1B)
REFL_END
struct Base2_t{
std::string Base2A;
std::string Base2B;
};
REFL_TYPE(Base2_t)
REFL_FIELD(Base2A)
REFL_FIELD(Base2B)
REFL_END
struct Sub_t : public Base1_t, public Base2_t{
std::string SubA;
};
REFL_TYPE(Sub_t, Bases<Base1_t, Base2_t>())
REFL_FIELD(SubA)
REFL_END
template<typename T>
void useIt(T *instance);
template<typename T>
void useIt(T *instance)
{
if constexpr(refl::descriptor::has_attribute<Bases>(refl::reflect<T>())){
constexpr auto bases = refl::descriptor::get_attribute<Bases>(refl::reflect<T>());
if constexpr (bases.descriptors.size) {
refl::util::for_each(bases.descriptors, [&](auto t) {
std::cout << "Base: " << t.name << std::endl;
useIt(static_cast<typename decltype(t)::type*>(instance));
});
}
}
std::cout << "Type: " << refl::reflect<T>().name << std::endl;
for_each(refl::reflect<T>().members, [&](auto member) {
std::cout << member.name << " = " << member(*instance) << std::endl;
});
}
int main(int argc, char* argv[])
{
Sub_t sub;
sub.SubA = "SubA";
sub.Base1A = "Base1A";
sub.Base1B = "Base1B";
sub.Base2A = "Base2A";
sub.Base2B = "Base2B";
std::cout << "TestReflCppBaseClass" << std::endl;
useIt(&sub);
std::cout << "TestReflCppBaseClass End" << std::endl;
return 0;
}
Output:
TestReflCppBaseClass
Base: Base1_t
Type: Base1_t
Base1A = Base1A
Base1B = Base1B
Base: Base2_t
Type: Base2_t
Base2A = Base2A
Base2B = Base2B
Type: Sub_t
SubA = SubA
TestReflCppBaseClass End
Is it possible to iterate over the base classes in any way? I'm thinking about something like this:
Or is this possible using attributes? I didn't find a solution for this, as "get_attribute" does not accept a template type like BaseClass.
If there is a ForEach for attributes, then it could be combined with this https://stackoverflow.com/a/21512908 to build something equivalent out of attributes. But I couldn't find a way to iterate over attributes either.
PS: You've build a great library.