Right. It's a bit complicated, but if you stick to this method you should be ok
First up:
Singleton.h
#ifdef BUILDING_DLL#define EXPORT __declspec(dllexport)#else#define EXPORT __declspec(dllimport)#endif// requires DLL export flags for win32!template< typename T >class EXPORT Singleton{public: static T & Instance( void ) { return mSingleton; } static T * InstancePtr( void ) { return &mSingleton; }protected: static T mSingleton;private: Singleton(); // Hide ctor. ~Singleton(); // Hide dtor. Singleton( Singleton const & ); // Hide copy ctor Singleton & operator = ( Singleton const & ); // Hide assignment operator};template< typename T >T Singleton< T >::mSingleton = T();
But that doesn't export the template! It only tells the compiler that any instantiation of the template will be exported. (which may cause problems. More on that later). So. When you are building your dll, which requires the template to be exported. You need to be able to export the related template specialization from your DLL. In this case Singleton<MyClass>
So. Since your template is likely to exist in some CommonGuff.lib you may need a bit of #define hackery to get the correct export/import used. The following assumes that BUILDING_MY_DLL is only defined when you are compiling the DLL that uses the template.
MyClass.h
// a hack that tells singleton.h to use DLL_EXPORT when compiling your dll.#ifdef BUILDING_MY_DLL#define BUILDING_LIB #endif#include "Singleton.h"class __declspec( dllexport ) MyClass : public Singleton< MyClass >{public: void Print( void ) { printf( "Hello!" ); }};
almost there. The final part is exporting the specialisation of Singleton<MyClass> from the dll. Which you can do like so:
MyClass.cpp
#include "MyClass.h"// You must also export the template instantiation Singleton< MyClass > into // the DLL you are compiling. That should be it!template __declspec( dllexport ) class Singleton<MyClass>;
This should now remove all of the warning C4251 messages when compiling in visual C++. (Which is actually the one warning that will tell you if you've done this properly or not - it might be a warning level 4 warning though - can't remember).
Anyhow. Now onto the problems.
* It's easy to forget to export the template specliasation, and that should be the first thing to check if you ever see any linker errors surrounding the Singleton class (i.e. can't find Singleton<MyClass>::blah())
* You can hit some very nasty problems if you are exporting a Singleton specialisation from two separate DLL's. Say you have Singleton<Renderer> and Singleton<AssetManager>. You may have problems compiling Singleton<Renderer> in cases like this:
Renderer.cpp
// This will include Singleton.h, which will mark the Singleton<> template// as dllimport.#include "AssetManager.h"// This will also include Singleton.h, but this time you want Singleton<> // to be declared dllexport (since we are exporting Singleton<renderer>)// This however will not happen, since Singleton.h has previously been included// and Singleton<> has already been defined as dllimport (since it was included// by AssetManager.h). #include "Renderer.h"
There are ways around the problem, but they really do end up being god awful #define quagmires, where you end up removing sentry, start defining things in different namespaces and all manner of other hateful bits of code.
Sadly. After you go to all the effort to use templates in that way (with DLL's), you realise you would have been better off writing the methods as macros instead. So.... write your singleton as a macro is my advice ;)
/// !!NOTE!! These forward slashes should actually be backslashes, but /// unfortunately gamedev's source tags remove them!#define SINGLETON_DEFINITION(T) /public:/ static T & Instance( void )/ {/ return mSingleton;/ }/ static T * InstancePtr( void )/ {/ return &mSingleton;/ }/protected:/ static T mSingleton;/private:/ T(){}/ ~T(){}/ T( T const & ) {}/ T& operator = ( T const & ) {return *this;}#define SINGLETON_IMPLEMENTATION(T)/ T T ::mSingleton = T();
then....
#include "Singleton.h"class __declspec( dllexport ) MyClass {public: void Print( void ) { printf( "Hello!" ); } SINGLETON_DEFINITION(MyClass)};
// myclass.cpp
#include "MyClass.h"SINGLETON_IMPLEMENTATION(MyClass)
(I've not checked the above macros, there may be errors!)
\edit I will mention that i personally think singleton's are abominations that should never be used. Just use a global instance. It's far easier to deal with just a simple:
DLL_EXPORT MyClass gMyClassInstance;