Reputation: 108
I have tried for the past days to solve this issue I have with C++. It may be trivial, but I could not find a solution and searching on the Internet got me nowhere, so I'll ask here.
I have a C++ wrapper Singleton
class, a superclass and a number of subclasses. I need the the instances of the subclasses to be singletons, and so I used the solution proposed here as it is the one fitting my needs the most. I need a map to act as a register from a string to the correct subclass. To make it concrete, here is the code:
// 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
}
Now, I have tried a number of things, let me show all that I have tried:
// 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;
}
This is the version I'm stuck with and it gives an error on the insert
saying:
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
I have tried using std::pair
instead of std::make_pair
, changed the definition of the map to:
template <class T : public MySuperclass>
std::unordered_map s_classes<LPCSTR, Singleton<T>> s_classes;
But to no avail, as the first resulted in the same error (also using the []
operator gave me issues with [name]
as no operator matches these operands
) and the second results in type errors.
As it stands, I need the classes to be singletons, and to ensure that they are singletons, and I need a register that links a unique string identifying the class to its singleton. Can anyone either explain why this is impossible or if there is something like Java's <? extends MySuperclass>
in C++ that can work here?
Upvotes: 1
Views: 270
Reputation: 39648
template <class T : public MySuperclass>
std::unordered_map s_classes<std::string, Singleton<T>> s_classes;
is not valid C++.
But you could simply make a std::unordered_map<std::string, MySuperclass*> s_classes
.
It's not necessary for our lookup map to know about the Singleton
pattern, it just needs to map onto a pointer to the corresponding subclass. We must use std::string
or std::wstring
as a key, because otherwise pointer comparison would be used between keys, not string comparison. Alternatively, we could provide a custom comparison operator.
The Singleton
itself can also be simplified. static
local variables are initialized upon the first use of the function, which is exactly the behavior that we want.
template <typename T>
class Singleton
{
static T *Instance()
{
static T instance{};
return &instance;
}
}
Our previous use of new
would have been a memory leak anyways, since delete
was never called.
Now, we can also update or MyRegister
accordingly.
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;
}
Upvotes: 1