0

I have a generic method in C#:

public T GetComponent<T>() where T : Component {
    foreach (Component component in this.components)
        if (component is T c)
            return c;

    return default(T);
}

I want to translate it in C++:

template<typename T>
T* GameObject::getComponent() const {
    if (!std::is_base_of<Component, T>::value)
        return nullptr;

    for (auto i = this->components->begin(); i != this->components->end(); i++)
        if (typeid(*i) == typeid(T))
            return dynamic_cast<T>(*i);

    return nullptr;
}

But it seems like neither typeid nor dynamic_cast cannot deal with generic types. How can I achieve it?

EDIT:

Component* GameObject::getComponent(const type_info& type) const {
    for (auto i = this->components->begin(); i != this->components->end(); i++)
        if (typeid(*i) == type)
            return *i;

    return nullptr;
}

Possible usage:

cg::SpriteRenderer2D* renderer = (cg::SpriteRenderer2D*)getComponent(typeid(cg::SpriteRenderer2D));

The only problem is that there is no check if the passed type derives Component. Also I'm not sure if I have to dereference i two times so typeid(**i). The first one from iterator to Component*. The second one from Component* to Component. Or I store a list of Component&.

Kaskorian
  • 426
  • 3
  • 18
  • What is the actual type of `i`? – Dai May 04 '20 at 06:11
  • `std::list::iterator` – Kaskorian May 04 '20 at 06:13
  • 1
    You can write your C# method much more easily: `public T GetComponent() where T : Component { return this.components.OfType().FirstOrDefault(); }` – SomeBody May 04 '20 at 06:20
  • 1
    What are storing in your array of `Component`? – Thomas Caissard May 04 '20 at 06:23
  • @SomeBody I know but I rewrote it so that I have a guideline about what I have to cover in the c++ function. Also, OfType is a bit less efficient because it goes through the whole list, also if an element was found. :) – Kaskorian May 04 '20 at 06:27
  • @ThomasCaissard Declaration from GameObject.h: `std::list* components;` – Kaskorian May 04 '20 at 06:29
  • 2
    @Matze: No, it doesn't go through the whole list, see https://stackoverflow.com/questions/7324033/what-are-the-benefits-of-a-deferred-execution-in-linq – SomeBody May 04 '20 at 06:32
  • Okay, then I was wrong. But the C# method works at least in comparison to the c++ function. And I need the c++ version – Kaskorian May 04 '20 at 06:35
  • 1
    C++ doesn't have reified generics - so `typeid(T)` or `typeid(T*)` won't work the way you want them to - so implementing anything like `.OfType()` in C++ will be very painful (see this: https://stackoverflow.com/questions/25873338/using-typeid-to-check-for-template-type ). You probably don't want to use RTTI either. So it's important that your `Component` type in C++ is self-describing. – Dai May 04 '20 at 07:01
  • 1
    If your C# code is meant to be implementing anything like `IServiceProvider` then please be-aware that it's an anti-pattern because you lose compile-time guarantees about what services (`Component` in your case) are available. This is why dependency-injection with individual ctor parameters wins-out over just injecting an `IServiceProvider` to every ctor. – Dai May 04 '20 at 07:05
  • 2
    I mean to say is that attempting to convert this C# into C++ the way you're doing it is like translating English into a different language by translating each word individually, ignoring global context and language-features. In order to provide a good answer we need to know what `getComponent()` is meant to do and how it's used - because I'm sure there's a better **idiomatic C++** way of achieving your desired end-result. I'm thinking you should be using strongly-typed object containers or something - doing casts in C++ is generally a bad idea because of the lack of RTTI and reflection. – Dai May 04 '20 at 07:08
  • What about the edit? No generics, no casting – Kaskorian May 04 '20 at 07:29
  • Maybe you already noticed that the naming is similar to unity's hierarchy. I wanted to try to implement a simple gameobject-component hierarchy like in unity. – Kaskorian May 04 '20 at 07:34
  • Of cause I know what `is` does and of cause I know that my 'solution' in the edit is not similar to `is` because it's not looking at the inheritance tree. It's just a working type comparison with my c++ knowledge because it seems like I cannot pass the information necessary for a `dynamic_cast` as parameters or template types. – Kaskorian May 04 '20 at 10:04
  • @matze Just completely ditch your “get component” concept and instead expose strongly-typed objects via distinct getters (and repetition in code can be solved with macros and other code-gen solutions). My rule of thumb is that if you have to up-cast an object-pointer anywhere then you’re doing something wrong (and that includes casting to a template parameter type) – Dai May 04 '20 at 13:37

0 Answers0