4 ms·
Not at the moment, no. But it's not rocket science. The macro essentially creates a struct like this one: struct S { // How many fields are in this struc
by Kristine1975 11y ago
Not at the moment, no. But it's not rocket science. The macro essentially creates a struct like this one:
struct S {
// How many fields are in this struct?
static constexpr unsigned int FIELD_COUNT = 5;
// Full specializations are not allowed inside classes, so add a dummy parameter <T> that is equivalent to S
template <unsigned int Index, typename T = S>
struct FieldTraits;
// Partial specialization for the first field
template <typename T>
struct FieldTraits<0, T> {
using type = int;
static constexpr std::size_t OFFSET = offsetof(S, anInt);
static constexpr const char* name() { return "anInt"; }
static constexpr type& value(S& self) { return self.anInt; }
};
// The first field itself
int anInt;
// Partial specialization for the second field
template <typename T>
struct FieldTraits<1, T> {
using type = bool;
static constexpr std::size_t OFFSET = offsetof(S, aBool);
static constexpr const char* name() { return "aBool"; }
static constexpr type& value(S& self) { return self.aBool; }
};
// The second field itself
bool aBool;
...
};
Now that we have the meta-information about the struct's fields, we can process them:
// Meta-function to process a struct's fields
template <typename T, unsigned int FieldIndex, unsigned int FieldCount>
struct ForEach {
template <typename Functor>
static void apply(T& object, Functor f)
{
// Get the field's value and call the functor with it
auto value = T::FieldTraits<FieldIndex>::value(object);
f(value);
// Next field
ForEach<T, FieldIndex + 1, FieldCount>::apply(object, f);
};
};
// Partial specialization to end iteration
template <typename T, unsigned int FieldCount>
struct ForEach<T, FieldCount, FieldCount> {
template <typename Functor>
static void apply(T& object, Functor f)
{
};
};
And finally a bit of syntactic sugar:
template <typename T, typename Functor>
void forEachField(T& object, Functor f)
{
ForEach<T, 0, T::FIELD_COUNT>::apply(object, f);
}
*(omitted for the sake of clarity: dealing with const objects, using rvalue references and std::forward for the functor to make the code work with non-copyable functors)
- dman 11y agoThanks for taking the time to write this!