Examples » Core » Reflection » String Conversion Trait

Exposing string conversion functions of a type.

Lets say you have a type Name, which is just a wrapper around an std::string. If you want it to be picked up by (de)serializers and other reflection consumers as just a string, you can add the StringConversionTrait to your type.

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

struct Name
{
    CUBOS_REFLECT;
    std::string inner;
};

The trait's constructor takes two functions: one to convert an instance of the to a string, and the other to convert a string to an instance of the type. The first method never fails, but the second one should return a boolean indicating whether the passed string was valid.

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

using cubos::core::reflection::StringConversionTrait;
using cubos::core::reflection::Type;

CUBOS_REFLECT_IMPL(Name)
{
    return Type::create("Name").with(
        StringConversionTrait{[](const void* instance) { return static_cast<const Name*>(instance)->inner; },
                              [](void* instance, const std::string& string) {
                                  static_cast<Name*>(instance)->inner = string;
                                  return !string.empty(); // Only accept non-empty strings.
                              }});
}

Now, we can access the trait from the reflected type:

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

    const auto& nameType = reflect<Name>();
    CUBOS_ASSERT(nameType.has<StringConversionTrait>());
    const auto& stringConversion = nameType.get<StringConversionTrait>();

Using the trait is as simple as:

    Name name{"Michael"};
    CUBOS_ASSERT(stringConversion.into(&name) == "Michael");
    CUBOS_ASSERT(stringConversion.from(&name, "John") == true); // Valid name, returns true
    CUBOS_ASSERT(name.inner == "John");
    CUBOS_ASSERT(stringConversion.from(&name, "") == false); // Invalid name, returns false
}