使用泛型将字符串的 C++ 映射到自定义 class

C++ map of string to custom class with generics

过去几天我一直在尝试解决我在 C++ 中遇到的这个问题。这可能是微不足道的,但我找不到解决方案,在网上搜索也无济于事,所以我会在这里问。

我有一个 C++ 包装器 Singleton class、一个 superclass 和一些 subclasses。我需要 subclasses 的实例是单例,所以我使用了 here 提出的解决方案,因为它最适合我的需要。我需要一个映射作为从字符串到正确子 class 的寄存器。为了使它具体,这里是代码:

// The Singleton class
template <typename T>
class Singleton
{
public:
    static T* Instance()
    {
        if (s_instance == NULL) { s_instance = new T(); }
        return s_instance;
    }
protected:
    static T* s_instance;
}

// Superclass
class MySuperclass
{
public:
    inline LPCSTR GetName() { return m_name; }
    
    virtual ~MySuperclass() { }
protected:
    LPCSTR m_name;
    
    MySuperclass(LPCSTR name) { m_name = name; }
}

// Example subclass
class MySubclass : public MySuperclass
{
    // subclass stuff
}

现在,我已经尝试了很多东西,让我展示一下我尝试过的所有东西:

// Where the problems begin
class MyRegister
{
public:
    static void Register()
    {
        Singleton<MySubclass> mySubclassSingleton;
        LPCSTR name = Singleton<MySubclass>::Instance()->GetName();
        s_classes.insert(std::make_pair(name, mySubclassSingleton));
    }
private:
    static std::unordered_map<LPCSTR, Singleton<MySuperclass>> s_classes;
}

这是我坚持使用的版本,它在 insert 上给出了一个错误:

E0304 no instance of overloaded function "std::map<_Kty, _Ty, _Pr, _Alloc>::insert [with _Kty=LPCSTR, _Ty=Singleton<MySuperclass>, _Pr=std::less<LPCSTR>, _Alloc=std::allocator<std::pair<const LPCSTR, Singleton<MySuperclass>>>]" matches the argument list

我尝试使用 std::pair 而不是 std::make_pair,将地图的定义更改为:

template <class T : public MySuperclass>
std::unordered_map s_classes<LPCSTR, Singleton<T>> s_classes;

但无济于事,因为第一个导致相同的错误(也使用 [] 运算符给我带来了 [name]no operator matches these operands 的问题),第二个导致类型错误。

就目前而言,我需要 classes 是单例,并确保它们是单例,并且我需要一个寄存器来链接一个唯一的字符串,该字符串将 class 标识到它的单例.任何人都可以解释为什么这是不可能的,或者 C++ 中是否有类似 Java 的 <? extends MySuperclass> 的东西可以在这里工作?

template <class T : public MySuperclass>
std::unordered_map s_classes<std::string, Singleton<T>> s_classes;

不是有效的 C++。 但是你可以简单地做一个std::unordered_map<std::string, MySuperclass*> s_classes。 我们的查找映射不需要知道 Singleton 模式,它只需要映射到指向相应子类的指针。我们必须使用 std::stringstd::wstring 作为键,否则键之间将使用指针比较,而不是字符串比较。或者,我们可以提供自定义比较运算符。

Singleton本身也可以简化。 static 局部变量在第一次使用函数时初始化,这正是我们想要的行为。

template <typename T>
class Singleton
{
    static T *Instance()
    {
        static T instance{};
        return &instance;
    }
}

我们之前对 new 的使用本来就是内存泄漏,因为从未调用过 delete

现在,我们也可以相应地更新或MyRegister

class MyRegister
{
public:
    static void Register()
    {
        MySubclass *instance = Singleton<MySubclass>::instance();
        s_classes.emplace(instance->GetName(), instance);
    }
private:
    static std::unordered_map<std::string, MySuperclass*> s_classes;
}