2016-01-25 8 views
-1

Я построения Entity-компонентов системы с помощью шаблона метапрограммирование я получаю либо Cannot convert from [base type] to [type user requested]& или Cannot convert NullComponent to [type user requested]& ошибки:.«Не удается преобразовать из 'A' до 'B &'

class Entity { 
public: 
    Entity() = default; 
    ~Entity() = default; 

    template<typename C, typename... Args> 
    void AddComponent(Args&&... args); 

    template<typename C> 
    C& GetComponent(); 

protected: 
private: 
    //...add/get helper methods here... 

    unsigned int _id; 
    std::vector<std::unique_ptr<IComponent>> _components; 
}; 

template<typename C> 
C& Entity::GetComponent() { 
    for(auto c : _components) { 
     if(std::is_base_of<a2de::IComponent&, C&>().value && std::is_same<decltype(c), C&>().value) { 
      return *c; //<-- error here 
     } 
    } 
    return NullComponent(); //<-- and here 
} 

EDIT

Эти варианты, кажется, работают в настоящее время.

template<typename C> 
const C& Entity::GetComponent() const { 
    for(auto& uc : _components) { 
     auto* c = dynamic_cast<C*>(uc.get()); 
     if(c && std::is_base_of<a2de::IComponent&, C&>().value && std::is_same<decltype(c), C&>().value) { 
      return *c; 
     } 
    } 
    throw std::runtime_error(std::string("Component not available.")); 
} 

ИЛИ

class Entity { 
public: 
    //same as before... 
protected: 
private: 
    //same as before... 
    a2de::NullComponent _null_component; 
}; 

template<typename C> 
const C& Entity::GetComponent() const { 
    for(auto& uc : _components) { 
     auto* c = dynamic_cast<C*>(uc.get()); 
     if(c && std::is_base_of<a2de::IComponent&, C&>().value && std::is_same<decltype(c), C&>().value) { 
      return *c; 
     } 
    } 
    return _null_component; 
} 
+0

анализом было бы легче, если вы вывесили полный образец, который вам хотите скомпилировать (в текущем коде отсутствуют компоненты, IComponent и NullComponent). – Rumburak

+0

и вы забыли уважение 'c' в decltype? -> 'std :: is_same (). value' ->' std :: is_same (). value' –

+0

В "кажется, работают сейчас «почему вы нуждаетесь в' std :: is_base_of' и 'std :: is_same'? Разве dynamic_cast не заботится обо всем, что вам нужно? Кроме того, я уверен, что ссылки в 'is_base_of' перестают корректно работать с кодом. – Rumburak

ответ

2

По крайней мере, три вещи:

  • В GetComponent() вы перебрать unique_ptr элементы и сравните их тип (всегда std::unique_ptr<IComponent>) с чем-то еще в std::is_same. Вы, вероятно, этого не хотите.
  • Вы возвращаете ссылку на временное окончательное возвращение.
  • return *c нуждается в dynamic_cast, если C == IComponent.

EDIT

также:

  • std::is_base_of не имеет смысла со ссылками. Даже с class NullComponent : IComponent {}; вы все равно получите std::is_base_of<IComponent&, NullComponent&>::value == false.
  • И вы не проверяете nullptr

В конце концов, мне кажется, что вы должны заменить ваш цикл с

for(auto& component : _components) { 
    auto* c = dynamic_cast<C*>(component.get()); 
    if (c) 
    { 
    return *c; 
    } 
} 
+0

см. Редактировать ....... – Casey

0

На высоком уровне, из того, что я могу выяснить, тип возврата не может использоваться для определения типа шаблона. Список параметров можно использовать для определения типа шаблона.

Так, например, это может работать -

template<typename C> 
void Entity::GetComponent(C *obj) { 
    for(auto c : _components) { 
     if(std::is_base_of<a2de::IComponent&, C&>().value && std::is_same<decltype(c), C&>().value) { 
      obj = c; //<-- error here 
      return; 
     } 
    } 
    obj = NULL; 
    return; //<-- and here 
} 

Надеется, что это помогает.

+0

Извините! Опечатка!! :) – buchipper

Смежные вопросы