Is there a better way to do this? (factory subclass enum switch pattern)

So I'm making a game and I have this annoying pattern I've been using for loading levels. I have a bunch of different "item" structures that all have the same style static create function, eg:

Exploder* Exploder::Create(const v3& position, const v3& scale, const quat& rot, int flags) {
	auto itemId = static_cast<int>(Engine::getActiveWorld()->itemManager.items.size());
	auto obj = new GameObject("snip...");
	obj->getTypeId() = itemId;
	Engine::getActiveWorld()->addObject(obj);

	auto itm = new Exploder({ obj });
	Engine::getActiveWorld()->itemManager.items.emplace_back(itm);

	return itm;
}

That part is fine, but I don't enjoy maintaining the massive switch statement that actually calls these.

Item* ObjectManager::createItem(ItemType type, const v3& pos, int flags, const v3& scale, const quat& rot, const string& customName) {
	Item* ptr;
	switch (type) {
	case ItemType::rope:
		ptr = RopeItem::Create(pos, scale, rot, flags);
		break;
	case ItemType::torch:
		ptr = Torch::Create(pos, scale, rot, flags);
		break;
.... snip 50 more item types

My mind goes to Rust enums, and I wonder if there's a better construct in C++ to use than ... this.

Thanks in advance!

Edit: ok! Big thanks to u/AKostur for suggesting static array. This was the cleanest idea, it took some finessing to get the construction timing right but it worked so hell yeah!

What I did:

Changed Create to return an Item* instead of the actual type, since it's always upcasted anyways, now the signatures are all exactly identical.

then in enums.hpp I declare an array like sugested:

class Item;
using ItemCreateAction = Item*(*)(const v3&, const v3&, const quat&, int);
extern std::array<ItemCreateAction, static_cast<size_t>(ItemType::_count)> ItemCreateFuncs;

struct ItemArrayPlacer {
public:
	constexpr ItemArrayPlacer(ItemType type, const ItemCreateAction& action) {
		ItemCreateFuncs[static_cast<size_t>(type)] = action;
	}
};

Previously I had tried a similar idea, but std::function seems not to be able to be constexpr, so changing to raw function pointers allows for constexpr-ing the constructor.

exploder.cpp after includes before any code:

const auto t = ItemArrayPlacer(ItemType::exploder, Exploder::Create);

now the object manager can just call the functions like so:

Item* ptr = nullptr;
auto typeIndex = static_cast<size_t>(type);
if (typeIndex < ItemCreateFuncs.size() && ItemCreateFuncs[typeIndex]) {
	ptr = ItemCreateFuncs[typeIndex](pos, scale, rot, flags);
}

Sweet! Code is now organized much better! Thanks for the ideas everyone!

reddit.com
u/snerp — 22 days ago
▲ 8 r/hardcorepunk+2 crossposts

"He won't make it to a third term..." - some relevant lyrics when the fat orange fuck announced his 2028 plans

What other political hardcore you guys feeling rn?

youtube.com
u/snerp — 3 days ago

Shorts this week kick ass

Great choices on the shorts this week! Really rewarding to push further on these maps!

reddit.com
u/snerp — 3 months ago
▲ 23 r/gameenginedevs+2 crossposts

Whipped up a new cloud and water shader after getting inspired by some great work by other devs here, what do you think?

u/snerp — 3 months ago