Daniel Ribeiro
Daniel Ribeiro

Reputation: 10234

Template function static variable

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?

Upvotes: 4

Views: 888

Answers (3)

R Sahu
R Sahu

Reputation: 206577

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.

Upvotes: 2

user2296177
user2296177

Reputation: 2837

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

Upvotes: 4

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122460

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

Upvotes: 5

Related Questions