Examples » Core » Reflection » Dictionary Trait

Exposing and using dictionary functionality of a type.

The DictionaryTrait trait is used to expose the dictionary functionality of a type. In this example, we will write a function which takes a type and an instance of that type, and prints its entries:

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

using cubos::core::reflection::DictionaryTrait;
using cubos::core::reflection::Type;

void printDictionary(const Type& type, const void* instance)
{
    const auto& dictionaryTrait = type.get<DictionaryTrait>();

Through the trait, we can access the size of the dictionary and its key and value types:

    auto dictionaryView = dictionaryTrait.view(instance);
    CUBOS_INFO("Dictionary with {} entries of key type {} and value type {}", dictionaryView.length(),
               dictionaryTrait.keyType().name(), dictionaryTrait.valueType().name());

We can also iterate over the entries of a dictionary and access them:

    if (!dictionaryTrait.keyType().is<int32_t>() || !dictionaryTrait.valueType().is<int32_t>())
    {
        CUBOS_INFO("This function does not support printing dictionary with key and value types other than int32_t");
        return;
    }

    for (auto [key, value] : dictionaryView)
    {
        CUBOS_INFO("{} -> {}", *static_cast<const int32_t*>(key), *static_cast<const int32_t*>(value));
    }
}

In this example, we're only supporting dictionaris which map int32_ts, but we could for example implement a printing function which supports all primitive types.

To make calling our function easier, we can add a convenience typed wrapper:

template <typename T>
void printDictionary(const T& dictionary)
{
    using cubos::core::reflection::reflect;

    printDictionary(reflect<T>(), &dictionary);
}

Using this function is now as simple as:

#include <cubos/core/reflection/external/map.hpp>
#include <cubos/core/reflection/external/primitives.hpp>

int main()
{
    std::map<int32_t, int32_t> map = {
        {1, 2},
        {2, 4},
        {3, 6},
        {4, 8},
    };
    printDictionary(map);

    // Dictionary with 4 entries of key type int32_t and value type int32_t
    // 1 -> 2
    // 2 -> 4
    // 3 -> 6
    // 4 -> 8
}

Its important to note that both the includes above are necessary, as we're reflecting the type std::map<int32_t, int32_t>, which also means reflecting int32_t.

Executing the sample should output:

    // Dictionary with 4 entries of key type int32_t and value type int32_t
    // 1 -> 2
    // 2 -> 4
    // 3 -> 6
    // 4 -> 8