#include #include struct DefaultSlotKey; template class Slot { protected: Type& doGet() { return value_; } void doSet(const Type& value) { value_ = value; } template void doEmplace(Args&&... args) { value_ = Type(std::forward(args)...); } private: Type value_; }; template class Repository : private Slots... { public: template Type& get() { static_assert(std::is_base_of, Repository>::value, "Please ensure that this type or this key exists in this repository"); return Slot::doGet(); } template void set(const Type& value) { static_assert(std::is_base_of, Repository>::value, "Please ensure that this type or this key exists in this repository"); Slot::doSet(value); } template void emplace(Args&&... args) { static_assert(std::is_base_of, Repository>::value, "Please ensure that this type or this key exists in this repository"); Slot::doEmplace(std::forward(args)...); } }; // Incomplete types used as compile-time keys. struct Key1; struct Key2; // Create a type for our repository. using MyRepository = Repository < Slot, // Let's pick the type of our slots. Slot >; int main() { MyRepository myRepository; myRepository.set("toto"); myRepository.set(42); std::cout << myRepository.get() << std::endl; // Print: "toto". std::cout << myRepository.get() << std::endl; // Print: 42. myRepository.emplace(4, 'a'); std::cout << myRepository.get() << std::endl; // Print: 42. return EXIT_SUCCESS; }