Closed stakira closed 1 month ago
Was able to get sth to work with
view = rfl::to_view(foo);
view.apply([](const auto& f) {
if (typeid(*f.value()) == typeid(uint32_t)) {
...
} else if (typeid(*f.value()) == typeid(float)) {
...
}
});
I have a feeling this might be the best way already?
Hi @stakira ,
yes, .apply(...)
is meant for exactly these kind of uses cases. The problem with runtime iteration is that you don't have any kind of type safety.
Here is how I would rewrite your example:
#include <type_traits>
const auto view = rfl::to_view(foo);
view.apply([](const auto& f) {
using Type = typename rfl::remove_cvref_t<decltype(f)>::Type;
if constexpr (std::is_same<Type, uint32_t*>()) {
...
} else if constexpr (std::is_same<Type, float*>()) {
...
}
});
The beauty about this solution is that you now have compile-time type safety. Once you are inside the branches of the constexpr if, the compiler will know that f.value()
is in fact an uint32_t*
or float*
.
By the way, you can also differentiate by name:
const auto view = rfl::to_view(foo);
view.apply([](const auto& f) {
if constexpr (f.name() == "f1") {
...
} else if constexpr (f.name() == "f2") {
...
}
});
Question: How would you like to see the documentation improved to make this a bit more clearer?
@stakira, does this resolve the issue? Can we close it?
Thanks!
I realized the apply()
is unrolling the tuple using recursive templates, therefore using a regular for loop is not possible.
And the "right way" to deal with this situation seems to be defining a template and its specializations, e.g.:
template <typename T>
void Print(const T& t) {}
void Print(const uint32_t& t) {}
void Print(const float& t) {}
view.apply([&](const auto& f) {
Print(*f.value());
});
My question is answered. Feel free to close.
Regarding documentation, I think what I'm trying to do is a very common use case. It would be really useful to mention examples we have above in the "Reflective programming" section. To be honest, when you have to put a name or index in the template, like view.get<"age">
or rfl::get<0>
, reflection is not all that useful. If you cannot supply names or indexes as variables, you will have to know the struct type beforehand, then it's not that different from just accessing fields in the normal way.
@stakira , all right, thank you for your feedback. I will improve the documentation based on your suggestions, because I think that you are right. This is a common use case.
I think the real problem is that this is documented in rfl::NamedTuple:
https://github.com/getml/reflect-cpp/blob/main/docs/named_tuple.md
But I don't think anyone facing this problem would check the documentation for rfl::NamedTuple and then also understand that rfl::to_view(...) creates the named tuple you need to iterate over your struct.
I'm seeking a way to implement an editor of arbitrary structs using immediate mode GUI. Imagine code like below:
Currently the
get<name|id>
orreplace<name|id>
must be static, which makes the above way to iterate over fields difficult. Is something like this possible to implement in or on top of reflect-cpp?