You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制模板化单例创建并实现高度通用,让同一类层次共用单例?

让同一类层次共用模板单例的实现方案

原代码中,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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 21:01:54