简体   繁体   中英

Is it possible to assign array values at compile-time through constexpr functions?

I am fairly new to templates and compile-time functions, and I am currently trying to write a basic entity-component-system (ECS) that will allow me to store generic types (components) in containers. I want functionality to be able to setup my containers at compile-time, and run-time. There are some instances in my application where I know for certain which components will always persist for an entity so I want to be able to set these up and reserve the slots at compile-time. There are then occasions where components will need to be removed/added at runtime dynamically.

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);

This seems to work, and when I hover over transform , I can see what is returned but obviously incorrect values as I can't construct the type using the arguments in the const function. 在此处输入图像描述

I have also tried to remove some of the const from the variables but then it complains that things aren't const or can't be evaluated.

I am looking to create a type of Component , with the arguments provided and then find a free slot in m_components to store it. Is something like this possible at compile-time? If anyone has suggestions on how I could achieve what I want, or improve the solution it would be much appreciated. There is some macro code that I haven't included here which generates the classes like ComponentStorageMapping , ComponentTypeInfo and m_componentStorage


Below is a more simplified/generic version as requested in the comments

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

For the record, I created another post ( https://gamedev.stackexchange.com/questions/176301/how-can-i-create-a-templated-function-to-add-components-to-their-necessary-conta ) before this one to see how I would approach this situation and didn't receive many suggestions so I just tried to do it myself and this is the problem I have encountered. There is another framework achieving what I'm trying to do in some way, but I don't quite understand what they're doing as it's all templates. Links to the framework are in the other post.

I don't think that is possible what do you want.

See what you have written for 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];
}

Do you want a constexpr method, that is also const , that add a component in a member of the class/struct.

And obviously you can't use it as follows

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

Yuo can't call AddElement() without an object of its type.

You should start with a constexpr object of type C

constexpr C<A, 50u>  ca;

and then use it to call 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);
// ....................................^^^

but if ca is constexpr you can't add elements in it and if ca isn't constexpr you can't use the result of AddElement() to initialize the value of a constexpr variable.

The only way to I see to solve this problem is initialize the ca object with all elements; something as

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

and then extract the reference to the components

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM