Reputation: 521
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.
Upvotes: 0
Views: 6796
Reputation: 503
You can go for typeid with a caution that it is not suitable for run time polymorphism. For example below.
#include <iostream>
template<class T>
void getType(T A) {
std::cout<<typeid(A).name()<<"\n";
}
class Base {
};
class Derived : public Base {
};
int main(){
getType(Base());
getType(Derived());
Derived *d = new Derived();
getType(d);
Base *b = d;
getType(b);
return 0;
}
Output:
4Base
7Derived
P7Derived
P4Base
Upvotes: 0
Reputation: 13269
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
.
Upvotes: 6
Reputation: 683
Do a template specialization:
template <typename T>
void DoDraw(EasyGraphics* canvas);
template<>
void DoDraw<char>(EasyGraphics* canvas)
{
canvas->drawText(displayData, Entity::GetX() + textXOfset, Entity::GetY() + (Entity::getHeight() / 4) - 3);
}
template<>
void DoDraw<wchar_t>(EasyGraphics* canvas)
{
canvas->drawBitmap(displayData, Entity::GetX() + textXOfset, Entity::GetY() + (Entity::getHeight() / 4) - 3, 60, 60, 0x0000FF00);
}
template <typename T>
void Button<T>::draw(EasyGraphics* canvas)
{
...
DoDraw(canvas);
}
*check the template argument, it's pretty weird to have const char*
and not just char
.
Upvotes: 1