4

I have a template function to give me a unique id based on the typename passed to it, like this:

template<typename T>
inline std::size_t get_component_type_id() noexcept
{
    static_assert(std::is_base_of<Component, T>::value, "T must be of type Component.");

    static size_t uniqueComponentId{__INTERNAL__::getUniqueComponentId()};

    return uniqueComponentId;
}

When I call get_component_type_id with BaseClass 10 times, I get the same id. That works perfectly.

However, I want to get the same id as well if I pass a child class to that function. When I call it with ChildClass, I get a different id. Why is that?

1

3 Answers 3

5

This is because an instantiation of a template, once instantiated, has nothing to do with a second instantiation of the same template. The two are seperate entities and get their own static variable.

PS: Here is a video where this occurs in an example: CppCon 2015: Arthur O'Dwyer “Lambdas from First Principles: A Whirlwind Tour of C++"”. The example starts aroung 6:00

Sign up to request clarification or add additional context in comments.

Comments

4

You can try adding a function that calls get_component_type_id() with Component as the template argument when the actual T is a child of Component.

template<class T>
auto fn() noexcept
{
    using type = std::conditional_t<std::is_base_of<Component, T>::value, Component, T>;
    return get_component_type_id<type>();
}

Comments

2

get_component_type_id<BaseClass> and get_component_type_id<ChildClass> are two different functions. Hence, you get two of static size_t uniqueComponentId, each with their own value.

Update, in response to comment by OP

Yes, it is possible. You could use:

template <typename T>
inline std::size_t get_component_type_id(T*, std::false_type) noexcept
{
   static size_t uniqueComponentId{__INTERNAL__::getUniqueComponentId()};
   return uniqueComponentId;
}

inline std::size_t get_component_type_id(BaseClass*, std::true_type) noexcept
{
   static size_t uniqueComponentId{__INTERNAL__::getUniqueComponentId()};
   return uniqueComponentId;
}

template<typename T>
inline std::size_t get_component_type_id() noexcept
{
   static_assert(std::is_base_of<Component, T>::value, "T must be of type Component.");
   return get_component_type_id((T*)nullptr, typename std::is_convertible<T, BaseClass>::type{});
}

However, it is fragile. If you want the same behavior for another class derived from Component, you will need to make substantial changes.

You will be better off using a virtual member function.

struct Component
{
   virtual size_t get_type_id() const = 0;
};

struct BaseClass : Component
{
   size_t get_type_id() const
   {
       static size_t uniqueComponentId{__INTERNAL__::getUniqueComponentId()};
       return uniqueComponentId;
   }
};

struct ChildClass : BaseClass {};

Now you can implement size_t get_type_id() const at any level in the inheritance hierarchy as you see fit.

1 Comment

Is it possible to achieve what I wanted?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.