如何限制模板化单例创建并实现高度通用,让同一类层次共用单例?
让同一类层次共用模板单例的实现方案
原代码中,Singleton<T>会为每个不同的T生成独立的类实例,因此Singleton<Base>和Singleton<Derived>是完全分离的单例,无法直接共用。要实现同一类层次共用同一个单例,需要修改模板的实例化逻辑,让派生类映射到基类的单例实例。
核心思路
通过类型映射,让所有属于同一类层次的类型(如Base及其派生类)都关联到同一个Singleton模板实例(即Singleton<Base>)。
具体实现方案
方案1:手动指定基类(简单直接)
修改全局Register函数,判断当前类型是否是Base的派生类,若是则强制使用Singleton<Base>的实例:
#include <type_traits> #include <unordered_set> class Base {}; class Derived : public Base {}; class Derived2 : public Derived {}; template<class T> class Singleton { public: static Singleton<T>& GetInstance() { static Singleton<T> singleton; return singleton; } void Register(T* Pointer) { pointers.insert(Pointer); } void DoWork() { /* 处理逻辑 */ } private: Singleton() {} std::unordered_set<T*> pointers; }; template<class T> void Register(T* Pointer) { // 若T是Base的派生类,使用Singleton<Base>;否则使用自身类型的单例 using TargetType = std::conditional_t<std::is_base_of_v<Base, T>, Base, T>; Singleton<TargetType>::GetInstance().Register(static_cast<TargetType*>(Pointer)); }
方案2:通用类型萃取(扩展性强)
定义SingletonKey类型 trait,为每个类型指定对应的单例关联键,让派生类自动关联到基类:
#include <type_traits> #include <unordered_set> class Base {}; class Derived : public Base {}; class Derived2 : public Derived {}; // 默认:类型自身作为单例键 template<typename T, typename = void> struct SingletonKey { using type = T; }; // 特化:所有Base的派生类,键为Base template<typename T> struct SingletonKey<T, std::enable_if_t<std::is_base_of_v<Base, T>>> { using type = Base; }; template<class T> class Singleton { public: static Singleton<T>& GetInstance() { static Singleton<T> singleton; return singleton; } void Register(T* Pointer) { pointers.insert(Pointer); } void DoWork() { /* 处理逻辑 */ } private: Singleton() {} std::unordered_set<T*> pointers; }; template<class T> void Register(T* Pointer) { using KeyType = typename SingletonKey<T>::type; Singleton<KeyType>::GetInstance().Register(static_cast<KeyType*>(Pointer)); }
效果验证
调用Register时,Base*、Derived*、Derived2*都会注册到同一个Singleton<Base>实例中:
int main() { Base b; Derived d; Derived2 d2; Register(&b); // 注册到Singleton<Base> Register(&d); // 注册到Singleton<Base> Register(&d2); // 注册到Singleton<Base> Singleton<Base>::GetInstance().DoWork(); // 处理所有注册的对象 return 0; }
内容的提问来源于stack exchange,提问作者window_handle
相关产品推荐
相关产品推荐

