Search code examples
c++templatestypesswitch-statementtypechecking

How do I check types within a template class in c++?


I have a Button class that can either display an image or a line of text, which I am trying to use a template implement.

If it's text, then the template type is: const char*

If its an image, then the template type is: const wchar_t*

Here is the method that needs to differentiate between the two types:

template <typename T>
void Button<T>::draw(EasyGraphics* canvas)
{
    canvas->setBackColour(colour);

    if (mouseOver)
    {
        canvas->setPenColour(EasyGraphics::BLACK, 4);
    }
    else
    {
        canvas->setPenColour(EasyGraphics::BLACK, 2);
    }

    canvas->drawRectangle(Entity::GetX(), Entity::GetY(), Entity::getWidth(), Entity::getHeight(), true);
    canvas->setFont(20, L"");
    canvas->setTextColour(textColour);

    switch (typeid(T))
    {
        // Button has display text
        case typeid(const char*):
        {
            canvas->drawText(displayData, Entity::GetX() + textXOfset, Entity::GetY() + (Entity::getHeight() / 4) - 3);
            break;
        }
        // Button has display image
        case typeid(const wchar_t*):
        {
            canvas->drawBitmap(displayData, Entity::GetX() + textXOfset, Entity::GetY() + (Entity::getHeight() / 4) - 3, 60, 60, 0x0000FF00);
            break;
        }
    }
}

I cannot seem to get the switch at the bottom to function correctly. I am not sure if a switch is the best way to go about it. Any advice would be appreciated, cheers.


Solution

  • Use type traits (and if constexpr) instead of typeid. For example:

    void g_char(const char*);
    void g_wchar_t(const wchar_t*);
    
    template <typename T>
    void f(T)
    {
        if constexpr (std::is_same_v<T, const char*>)
        {
            g_char(T());
        }
        else if constexpr (std::is_same_v<T, const wchar_t*>)
        {
            g_wchar_t(T());
        }
    }
    

    http://coliru.stacked-crooked.com/a/08e9e66ed5c776a4

    The reason a switch doesn't work here is that the condition must be implicitly convertible to an integral type, and std::type_info (what typeid returns) isn't.

    But then if you try keeping the typeid expressions, you have the problem of compile-time type checking when you try calling drawText or drawBitmap. Both calls must be valid unless you use constexpr branches (if constexpr). However, the conditions must then be compile-time constants, where typeid cannot be used. So instead, you can use type traits, and in particular, std::is_same.