Examples » Core » Reflection » Fields Trait

Exposing the fields of a type.

For structured types, like classes and structs, you might want to expose its public fields using the FieldsTrait trait. In this example, we'll expose the fields of the following type:

#include <cubos/core/reflection/reflect.hpp>

struct Person
{
    CUBOS_REFLECT;
    int32_t age;
    float weight;
    bool dead;
};

In its reflection definition, we'll add the FieldsTrait trait to it with each of the fields we want to expose:

#include <cubos/core/reflection/traits/fields.hpp>
#include <cubos/core/reflection/type.hpp>

// Since we're exposing fields of primitive types (int32_t, float and bool), its important to
// include the header which defines their reflection.
#include <cubos/core/reflection/external/primitives.hpp>

using cubos::core::reflection::FieldsTrait;
using cubos::core::reflection::Type;

CUBOS_REFLECT_IMPL(Person)
{
    return Type::create("Person").with(FieldsTrait()
                                           .withField("age", &Person::age)
                                           .withField("weight", &Person::weight)
                                           .withField("dead", &Person::dead));
}

Accessing this trait is the same as with any other trait:

int main()
{
    using cubos::core::reflection::reflect;

    const auto& personType = reflect<Person>();
    CUBOS_ASSERT(personType.has<FieldsTrait>());
    const auto& fields = personType.get<FieldsTrait>();

We can iterate over the fields of the type with it:

    for (const auto& field : fields)
    {
        CUBOS_INFO("Field {} of type {}", field.name(), field.type().name());
    }

This should output:

    // Field 'age' of type 'int32_t'
    // Field 'weight' of type 'float'
    // Field 'dead' of type 'bool'

Its also possible to access the fields of an instance of the type, and iterate over them:

    Person person{.age = 21, .weight = 68.4F, .dead = false};
    auto view = fields.view(&person);

    for (auto [field, value] : view)
    {
        if (field->type().is<int32_t>())
        {
            CUBOS_INFO("Field {}: {}", field->name(), *static_cast<int32_t*>(value));
        }
        else if (field->type().is<float>())
        {
            CUBOS_INFO("Field {}: {}", field->name(), *static_cast<float*>(value));
        }
        else
        {
            CUBOS_INFO("Field {}: unsupported type {}", field->name(), field->type().name());
        }
    }
    // Field 'age': 21
    // Field 'weight': 68.4
    // Field 'dead': unsupported type 'bool'

Its also possible to access the fields by name:

    *static_cast<float*>(view.get("weight")) += 20.0F;
    CUBOS_INFO("New weight: {}", person.weight); // 88.4
}
// New weight: 88.4