Reputation: 18585
This post is what I just read.
The way he implements Singleton in C++ confuses me. I got several Questions about it and here is his code:
template<typename T>
class Singleton {
public:
static T& getInstance() { //Question 1
return instance;
}
private:
static T instance;
};
class DebugLog : public Singleton<DebugLog> { //Question 2
public:
void doNothing() {}
};
Question
I think we should put the static T& getInstance()
's definition outside of the class body, right?
He tries to make class DebugLog
a singleton class, but when he inherits Singleton<DebugLog>
, the DebugLog
doesn't already exist, right? If right, then how can the template class Singleton
instantiate an un-existent class?
Upvotes: 0
Views: 751
Reputation: 153919
The C++ standard doesn't speak of “existence” with regards to classes (or anything
else). At the point of template instantiation, name lookup finds
DebugLog
, and finds that it is a class (thus, a type). At that point,
it is an incomplete type, and there are only limited things you can do
with an incomplete type. If the class template which is instantiated
doesn't do anything that requires a complete type (and Singleton
doesn't), then there is no problem. (Note that only the class
definition is instantiated at this point; class member functions will
not be instantiated until they are used.)
I might add that there is still one important thing missing from the
code you posted: there is no definition for the declaration
Singleton::instance
. You still need to add a:
template<typename T> T Singleton<T>::instance;
somewhere.
Upvotes: 1
Reputation: 477040
1) Nope, it doesn't matter how you structure your code. Singleton
isn't a class, by the way: It's a template. Since the full template definition must be visitible at any instantiation site anyway, you might as well define everything inline.
2) class DebugLog : public Singleton<DebugLog>
is fine. We are not inheriting from a non-existing class; rather, we are inheriting from the class Singleton<DebugLog>
. Templates can be instantiated on incomplete types. (There are several rules what you can and cannot do with such a type parameter.)
For example, template <typename T> class Foo { };
can certainly be instantiated on any type without problem. More interestingly, template <typename T> struct PointerFactory { typedef T * type; };
can be instantiated on any type, complete or not. In the present situation, the purpose of the template parameter in the CRTP is solely to inform the base class of its eventual derived type, so this is entirely fine.
Upvotes: 5
Reputation: 3089
You must use a pointer to T in this case:
template<typename T>
class Singleton {
public:
static T& getInstance() {
static T * instance = NULL;
if (!instance)
instance = new T;
return *instance;
}
};
class DebugLog : public Singleton<DebugLog> { //Question 2
public:
void doNothing() {}
};
Upvotes: -3