Можно ли присвоить значения массива во время компиляции через функции constexpr? - PullRequest
0 голосов
/ 27 октября 2019

Я довольно новичок в шаблонах и функциях времени компиляции, и в настоящее время я пытаюсь написать базовую сущность-компонент-систему (ECS), которая позволит мне хранить универсальные типы (компоненты) в контейнерах. Я хочу, чтобы функциональность могла настраивать мои контейнеры во время компиляции и во время выполнения. В моем приложении есть несколько случаев, когда я точно знаю, какие компоненты всегда будут существовать для сущности, поэтому я хочу иметь возможность их настроить и зарезервировать слоты во время компиляции. Тогда бывают случаи, когда компоненты нужно будет удалять / добавлять динамически во время выполнения.

template <typename T, size_t N>
struct ComponentArray {
public:
    template<typename... Args>
    constexpr const T& AddComponent(const uint64_t entity, Args &&... args) const
    {
        //T component{ std::forward<Args>(args)... }; //i want to be able to do something like this..
        //m_components[0] = component; //create the component and give it a slot, but this is const
        return m_components[0];
    }

    std::array<T, N>    m_components = {};
    std::array<T, N>    m_entityIds = {};
    uint32_t            m_used = 0;
};

template <uint64_t entityId, typename Component, typename ... Args>
constexpr const Component& AddComponentCT(Args&&... args)
{
    constexpr uint64_t componentHash = GetHashForString(ComponentTypeInfo<Component>::m_name, ComponentTypeInfo<Component>::m_nameLength);
    constexpr uint64_t storageHash = ComponentStorageMapping<componentHash>::m_hash;
    static_assert(storageHash == componentHash);

    constexpr const auto& componentStorage = ComponentStorageMapping<componentHash>::m_componentStorage;

    constexpr const Component& rComponent = componentStorage.AddComponent(entityId /*std::forward<Args>(args)...*/);

    return rComponent;
}


constexpr const TransformComponent transform = AddComponentCT<ENTITY_ID, TransformComponent>(5.0f, 5.0f, 5.0f);

Это работает, и когда я нахожу указатель мыши над transform, я вижу, что возвращается, но, очевидно, неверные значенияпоскольку я не могу построить тип, используя аргументы в функции const. enter image description here

Я также пытался удалить некоторые константы из переменных, но потом жалуется, что вещи не константны или не могут быть оценены.

Я пытаюсь создать тип Component с предоставленными аргументами, а затем найти свободный слот в m_components для его хранения. Возможно ли что-то подобное во время компиляции? Если у кого-то есть предложения о том, как я могу достичь того, чего хочу, или улучшить решение, это будет очень цениться. Здесь есть некоторый макрос, который я не включил, который генерирует классы, такие как ComponentStorageMapping, ComponentTypeInfo и m_componentStorage


Ниже приведена более упрощенная / универсальная версия, запрошенная в комментариях.

struct A
{
    float x, y, z;
};

struct B
{
    int i, j, k;
};

template <typename T, size_t N>
struct C {
public:
    template<typename... Args>
    constexpr const T& AddToArray(Args &&... args) const
    {
        //T element{ std::forward<Args>(args)... }; //i want to be able to do something like this..
        //m_array[0] = element; //create the component and give it a slot, but this is const
        return m_array[0];
    }

    std::array<T, N>    m_array = {};
};


template <typename T, typename ... Args>
constexpr const T& AddElement(Args&&... args)
{
    constexpr const T& element = C<T, 50>::AddToArray(/*std::forward<Args>(args)...*/);

    return element;
}


constexpr const A& someArrayElement = AddElement<A>(5.0f, 5.0f, 5.0f); //this would point to C<A,50>::m_array[0], fully constructed
constexpr const A& someArrayElement2 = AddElement<A>(10.0f, 10.0f, 10.0f); //this would point to C<A,50>::m_array[1], fully constructed

constexpr const B& someArrayElement3 = AddElement<B>(1, 1, 1); //this would point to C<B,50>::m_array[0], fully constructed
constexpr const B& someArrayElement4 = AddElement<B>(2, 2, 2); //this would point to C<B,50>::m_array[1], fully constructed

Для записи я создал еще один пост (https://gamedev.stackexchange.com/questions/176301/how-can-i-create-a-templated-function-to-add-components-to-their-necessary-conta) до этого, чтобы посмотреть, как я буду подходить к этой ситуации, и не получил много предложений, поэтому я просто попытался сделать это сами это - проблема, с которой я столкнулся. Есть другая структура, достигающая того, что я пытаюсь сделать в некотором роде, но я не совсем понимаю, что они делают, поскольку это все шаблоны. Ссылки на структуру находятся в другойпочта.

1 Ответ

0 голосов
/ 27 октября 2019

Я не думаю, что это возможно, что вы хотите.

Посмотрите, что вы написали для AddToArray()

template<typename... Args>
constexpr const T& AddToArray(Args &&... args) const
{
    //T element{ std::forward<Args>(args)... }; //i want to be able to do something like this..
    //m_array[0] = element; //create the component and give it a slot, but this is const
    // .......................^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    return m_array[0];
}

Хотите ли вы метод constexpr, которыйтакже const, который добавляет компонент в член класса / структуры.

И, очевидно, вы не можете использовать его следующим образом

constexpr const A& someArrayElement = AddElement<A>(5.0f, 5.0f, 5.0f);
constexpr const A& someArrayElement2 = AddElement<A>(10.0f, 10.0f, 10.0f);

Юо не может вызвать AddElement() без объекта его типа.

Вы должны начать сconstexpr объект типа C

constexpr C<A, 50u>  ca;

, а затем использовать его для вызова AddElement()

constexpr const A& someArrayElement = ca.AddElement<A>(5.0f, 5.0f, 5.0f);
constexpr const A& someArrayElement2 = ca.AddElement<A>(10.0f, 10.0f, 10.0f);
// ....................................^^^

, но если ca равен constexpr, вы не сможетедобавьте в него элементы, и если ca не constexpr, вы не можете использовать результат AddElement() для инициализации значения переменной constexpr.

Единственный способ увидетьрешить эту проблему - инициализировать объект ca со всеми элементами;что-то вроде

constexpr C<A, 50u>  ca { A{5.0f, 5.0f, 5,0f}, A{10.0f, 10.0f, 10.0f} /* etc ... */ };

, а затем извлечь ссылку на компоненты

constexpr A & someArrayElement  = ca.GetElement(0);
constexpr A & someArrayElement2 = ca.GetElement(1);
...