Получить наиболее производный тип от std :: type_index для компонента - PullRequest
0 голосов
/ 10 января 2020

У меня есть следующий код, который позволяет мне использовать систему компонентов объекта. Однако из-за природы шаблонов добавление компонентов из std::vector<HE2_Component*> вызывает их добавление с typeID HE2_Component вместо их наиболее производной формы (пример внизу кода). Как я могу заставить это правильно идентифицировать типы компонентов?

template<typename T,
    typename = std::enable_if_t<std::is_base_of_v<HE2_Component, T>>>
    void addComponent(T* component)
{
    components.insert(std::make_pair(std::type_index(typeid(T)), component));
    component->host = this;
}


template<typename CompType,
    typename = std::enable_if_t<std::is_base_of_v<HE2_Component, CompType>>>
    inline void removeComponent()
{
    auto it = components.find(std::type_index(typeid(CompType)));

    if (it == components.end())
        return;

    components.erase(it->first);
}


template<typename CompType,
    typename = std::enable_if_t<std::is_base_of_v<HE2_Component, CompType>>>
    inline CompType* getComponent()
{
    auto it = components.find(std::type_index(typeid(CompType)));

    if (it == components.end())
    {
        throw std::runtime_error("Object does not contain this component!");
        return nullptr;
    }


    return dynamic_cast<CompType*>(it->second);
}


//EXAMPLE HERE 
//Setup
HE2_ComponentOwner* obj = new HE2_ComponentOwner();
HE2_ComponentOwner* obj2 = new HE2_ComponentOwner();

class A : virtual public HE2_Component { double f = 0.0; };
class B : virtual public HE2_Component { float b = 0.0f; };
class C : public HE2_Component { int x = 0; };

//Add some components from a vector to obj
std::vector<HE2_Component*> comps = { new A(), new B(), new C() };
for (auto x : comps)
    obj->addComponent(x);

//Add some manually to obj2
obj2->addComponent(new A());
obj2->addComponent(new B());
obj2->addComponent(new C());

//This doesn't work
A* a = obj->getComponent<A>();
B* a = obj->getComponent<B>();
C* c = obj->getComponent<C>();

//This does work

A* a = obj2->getComponent<A>();
B* b = obj2->getComponent<B>();
C* c = obj2->getComponent<C>();

1 Ответ

3 голосов
/ 10 января 2020

Вам нужно сделать typeid(*component), чтобы получить тип динамического c указываемого объекта, а не объявленный тип его typename или указателя на него.

Естественно, typeid(T) всегда будет T. Таким образом, если вы передаете указатель менее производного типа T* component, то typeid(T) не эквивалентен typeid(*component).

Кроме того, если вы пытались typeid(component) без разыменования, то вам следует получить тип указателя, а не тип того, на что он указывает, что не должно быть правильным.

Наконец, хотя это кажется уже гарантированным в вашем случае, стоит отметить, что объекты должны быть полиморфными c, чтобы это работало, т. Е. Иметь хотя бы одну виртуальную функцию-член. В противном случае RTTI, в котором это необходимо, не будет существовать.

...