Home > Blockchain >  C combine maps of enums
C combine maps of enums

Time:10-30

Let's imagine I have some class hierarchy for a game. Like this: PhysicalObject is parent of BaseUnit is parent of BaseArcher and so on... And each hierarchy level adds its own stats.

Any PhysicalObject - has speed and size. Any BaseUnit - hit points.

I want it to be used as enums, so:

enum class PhysicalObjectStats { speed, size };
enum class BaseUnitStats { hitpoints };

Of course, BaseArcher must include stats of PhysicalObject and BaseUnit. How to make such an architecture? I've tried to implement it in such a simple way, using just map and dynamic polymorphism, but it doesn't compile (with a good reason, honestly):

https://coliru.stacked-crooked.com/a/8496247abd3e6f41

Also, I've tried to create a specific StatsHolder class and it works, but looks awful in all possible use-cases (setting and getting values). Actually, I cannot get value outside of class without down-casting:

https://coliru.stacked-crooked.com/a/46f4f4aec6a22c57

In addition, my stats may be not only int, but also bool and some other types. I tried to use std::variant for them and it works fine, but I don't want to think about it, using "GetStats()" method. So, ideally I want to have such an interface:

std::shared_ptr<PhysicalObject> unit = std::make_shared<BaseUnit>();
unit->SetValue<int>(PhysicalObjectStats::speed);
std::cout << unit->GetValue<bool>(BaseUnitStats::HasArmor);

And this makes the task even more difficult. Any suggestions of how it may be done in a good way?

CodePudding user response:

I don't see the point of map and enum whereas regular member seems to do the job:

struct PhysicalObject
{
    int speed = 0;
    int size = 0;
};
struct BaseUnitStats : PhysicalObject
{
// or composition:
// physicalObject PhysicalObject;
    int hitpoints = 0;
};

For your StatsHolder class:

template<class StatsEnum>
struct StatsHolder
{
    void SetStats(StatsEnum stat, int value) { stats[stat] = value; }
    int GetStats(StatsEnum stat) const { return stats.at(stat); }
private:
    std::map<StatsEnum, int> stats;
};

Derived classes have to use using:

struct BaseUnit : PhysicalObject, StatsHolder<BaseUnitStats> {
    using PhysicalObject::GetStats;
    using StatsHolder<BaseUnitStats>::GetStats;
    using PhysicalObject::SetStats;
    using StatsHolder<BaseUnitStats>::SetStats;

    BaseUnit() { SetStats(BaseUnitStats::hitpoints, 300); }
};

Demo

  • Related