I am trying to link an enum value to some class object so that I can manipulate the object by only using the enum value. I initially wanted to use a templated approach for learning purposes and the fact it would allow some compile-time computations.
After the initial implementation I've found myself in a situation where it seems like I need some sort of runtime code as well and I'm backtracking on the entire approach thinking that templating it is useless as I could achieve exactly the same thing with less obscure code just using polymorphism alone albeit introducing some call overhead.
enum Fruit {
All,
Orange,
Banana,
Mango
};
static const int FRUIT_COUNT = 4;
class BasketBase
{
public:
int m_otherFruitsBitfield;
};
template <Fruit T = Fruit::All>
class Basket {};
template<>
class Basket<Orange> : public BasketBase
{
public:
void Open() { printf("Basket (Oranges) - Open\n"); }
static Basket<Orange> m_basket;
};
template<>
class Basket<Banana> : public BasketBase
{
public:
void Open() { printf("Basket (Bananas) - Open\n"); }
void Throw() { printf("Basket (Bananas) - Throwing"); }
void Drop() { printf("Basket (Bananas) - Dropping"); }
int m_numBananas;
static Basket<Banana> m_basket;
};
Basket<Orange> Basket<Orange>::m_basket;
Basket<Banana> Basket<Banana>::m_basket;
template<Fruit T>
Basket<T>& GetBasket()
{
return Basket<T>::m_basket;
}
template<Fruit T>
void OpenBasket()
{
GetBasket<T>().Open();
}
int main() {
OpenBasket<Orange>();
OpenBasket<Banana>();
GetBasket<Orange>().m_otherFruitsBitfield = (1 << Banana) | (1 << Mango);
GetBasket<Banana>().m_otherFruitsBitfield = (1 << Mango);
//opening the basket should now open every other basket in the bitfield
int orangeBitfield = GetBasket<Orange>().m_otherFruitsBitfield;
for (int i = 0; i < FRUIT_COUNT; ++i)
{
Fruit fruit = static_cast<Fruit>(i);
if (orangeBitfield & fruit)
{
//OpenBasket(fruit); //runtime
//OpenBasket<fruit>() //nope
}
}
}
The code above is a simplified version, but serves the same purpose. The aim of this was to have some sort of shared object (Basket
) that would be tied to an individual enum value (Fruit
), and client code could call into the object by passing the enum. Each Basket
does share some common functionality, like Open
, but outside of that is completely independent and may contain specific data to the fruit being held.
Using the above approach I was able to compute all of the bitfields/object initializing at compile-time since I knew the data upfront, however otherFruitsBitfield
can now change at runtime which means I can't use the templated versions of GetBasket<>()
and would need a runtime one. Same applies to another variable which stores the currently viewed basket.
To fix this, I can think to add some virtual calls to the base class and override them, but then I question what's the point in using the template? I can achieve the same thing by storing a list of BasketBase*
and just doing everything at runtime but I would like to get out of my comfort zone regarding implementation.
Am I missing something here or is this not a valid use of a template? Could anyone provide some more information on these issues and any potential solutions?