#include #include #include #include namespace details { template auto damage(T const* obj, double total, int) -> decltype(obj->damage(total)) { return obj->damage(total); } template double damage(T const* obj, double total, double) { return total; } template auto defense(T const* obj, double total, int) -> decltype(obj->defense(total)) { return obj->defense(total); } template double defense(T const* obj, double total, double) { return total; } } class Item_Base { public: virtual ~Item_Base() = default; virtual double damage() const = 0; virtual double defense() const = 0; }; template class Item : public Item_Base, public Components... { public: Item(Components&&... components) : Components(std::forward(components))... { } double damage() const override { double total{}; ((total = details::damage(this, total, 0)), ...); return total; } double defense() const override { double total{}; ((total = details::defense(this, total, 0)), ...); return total; } }; struct Attack { double damage(double) const { return dmg; } double dmg{}; }; struct Defend { double defense(double) const { return def; } double def{}; }; struct Damage_Multiplier { double damage(double total) const { return factor * total; } double factor{1.0}; }; struct Defense_Multiplier { double defense(double total) const { return factor * total; } double factor{1.0}; }; struct Named { std::string name{}; }; using Weapon = Item; using Armor = Item; using Shield = Item; using Sword = Item; int main() { std::vector items { new Weapon { Attack{5.0} }, new Armor { Defend{10.0} }, new Shield { Defend{2.0}, Attack{2.5}, Defense_Multiplier{2.5} }, new Sword { Named{"Excalibur"}, Attack{5.0}, Damage_Multiplier{5.0} } }; assert(items[0]->damage() == 5.0); assert(items[1]->defense() == 10.0); assert(items[2]->damage() == 2.5); assert(items[2]->defense() == 5.0); assert(static_cast(items[3])->name == "Excalibur"); assert(items[3]->damage() == 25.0); }