3

Possible Duplicate:
Why can templates only be implemented in the header file?

I realise that there are already few topics like this on SO but I did not find any that would answer my problem.

I have already written my template singleton class using this tutorial http://www.codeproject.com/Articles/4750/Singleton-Pattern-A-review-and-analysis-of-existin

but unfortunately I keep on getting errors :

/home/USER/testcode/cpp_workshop/main.cpp:-1: error: undefined reference to `Singleton::Instance()' :-1: error: collect2: ld

my singleton.h

#ifndef SINGLETON_H
#define SINGLETON_H

template <typename T>
class Singleton
{
public:
    static T& Instance();

protected:
    virtual ~Singleton();
    inline explicit Singleton();

private:
    static T* _instance;
    static T* CreateInstance();
};

template<typename T>
T* Singleton<T>::_instance = 0;

#endif // SINGLETON_H

singleton.cpp

#include "singleton.h"
#include <cstdlib>

template <typename T>
Singleton<T>::Singleton()
{
    assert(Singleton::_instance == 0);
    Singleton::_instance = static_cast<T*>(this);
}

template<typename T>
 T& Singleton<T>::Instance()
{
    if (Singleton::_instance == 0)
    {
        Singleton::_instance = CreateInstance();
    }
    return *(Singleton::_instance);
}

template<typename T>
inline T* Singleton<T>::CreateInstance()
{
    return new T();
}

template<typename T>
Singleton<T>::~Singleton()
{
    if(Singleton::_instance != 0)
    {
        delete Singleton::_instance;
    }
    Singleton::_instance = 0;
}

and that's how I call it (with normall - not templated or anything - class Game ) Singleton<Game>::Instance().run();

Community
  • 1
  • 1
Patryk
  • 22,602
  • 44
  • 128
  • 244
  • Have you included the header file in main.cpp? – Eamonn McEvoy Jul 12 '12 at 13:23
  • @EamonnMcEvoy Yes I did include both of them (`game.h` and `singleton.h`) – Patryk Jul 12 '12 at 13:25
  • Template function definitions must be visible to the compiler at the places where these functions are used. Therefore you cannot place them into separate `.cpp` file. – n0rd Jul 12 '12 at 13:28
  • Btw, you should know that your singleton never gets deleted. Google "Meyers' singleton". You might also want to read the chapter on singletons from Alexandrescu's *Modern C++ Design*. – Paul Manta Jul 12 '12 at 13:34
  • @PaulManta Can you explain why it never gets deleted ? – Patryk Jul 13 '12 at 06:43
  • @Patryk The singleton object never goes out of scope, so the destructor is never called. – Paul Manta Jul 13 '12 at 07:29
  • @PaulManta But doesn't it 'go out of scope' when the program end ? (when function main finishes) – Patryk Jul 13 '12 at 08:14
  • @Patryk Yes, but only the pointer itself is destroyed. The data it points to (the singleton instance) never has its destructor called. Take a look at Meyers' singleton. It's a lot simpler and more robust than your current version. – Paul Manta Jul 13 '12 at 08:30
  • How is your solution preventing me to do 'Game g; g.run();'? – Benji Mizrahi Jan 23 '14 at 12:56
  • @bmm constructor is protected. – Patryk Jan 23 '14 at 15:51
  • But if Game's constructor is public, I will be able to write 'Game g;' So there can be multiple Game objects in the system. This Singleton class template cannot prevent it, right? – Benji Mizrahi Jan 24 '14 at 14:43
  • @bmm But here it's protected (maybe it would have been better to make it private) therefore you can't use `Game g;`. – Patryk Jan 24 '14 at 14:50
  • Sorry I am confused, there is no Game class in this example. All operations are on template type T. I can define my own class MyGame with a public constructor. I still could not understand why it makes sense to use this singleton template pattern rather than embedding the Singleton pattern into my Game class. – Benji Mizrahi Jan 24 '14 at 15:21

3 Answers3

3

Put your method definitions under your class definition in the header, and delete your cpp. Templated methods and methods of templated classes must be defined in headers (with a couple hackish exceptions).

Per request, here are the 'hackish exceptions':

  • 1) See @Desmond Hume's answer
  • 2) Only use the templated class from the cpp in which the methods are defined. For example, you can declare/define a templated class in an unnamed namespace in a cpp, that's just fine.
David
  • 27,652
  • 18
  • 89
  • 138
  • It did compile with that :) Hopefully it will not cause any problems later on in runtime... – Patryk Jul 12 '12 at 13:30
  • @Dave What those "hackish exceptions" would be? – Desmond Hume Jul 12 '12 at 13:48
  • @DesmondHume Edited to include them. – David Jul 12 '12 at 13:52
  • @Dave Seen your edit, hence another intrigue: since when the language's built-in feature is hackish? – Desmond Hume Jul 12 '12 at 13:52
  • @DesmondHume The exception you mentioned has always been considered hackish. Exception #2 is fine if it's all in an unnamed namespace, not hackish at all, otherwise I can't think of a legitimate use. It's 'fragile' at best (if anyone uses it from another translation unit it won't work). Thanks for the downvote btw. – David Jul 12 '12 at 13:55
  • @Dave Then C++ standard library must be "fragile" too? Quote: libstdc++ contains the explicit instantiation of std::basic_string,allocator > (which is std::string) so every time you use functions of std::string, the same function code doesn't need to be copied to objects. The compiler only need to refer (link) those to libstdc++. Source: http://stackoverflow.com/questions/2351148/explicit-instantiation – Desmond Hume Jul 12 '12 at 13:59
2

You could put the definition of your Singleton class into the header file or you could keep the separation of declarations (the header) and definitions (the .cpp file) as it is now if you like it better and explicitly instantiate the Singleton class with each of the types you are going to use it with. To explicitly instantiate Singleton class, try putting the following at the end of the .cpp file:

template
class Singleton<Game>;

With another type it would look in the same way:

template
class Singleton<AnotherGame>; // just for example
Desmond Hume
  • 8,037
  • 14
  • 65
  • 112
0

Its not possible to separate the definiton (header file) and implementation (cpp) of a templated class. So you have one of two solutions:

1- implement everything in the header file .h. something like this

template <typename T>
class Singleton
{
public:
    static T& Instance(){}

protected:
    virtual ~Singleton(){}
    inline explicit Singleton(){}

private:
    static T* _instance;
    static T* CreateInstance(){}
};

Another solution is to rename your .cpp class to .hpp. Don't include the .h file inside the .hpp file, but the other way around. i.e. include .hpp file inside .h file

I personally prefer the first solution

Cheers

Moataz Elmasry
  • 2,509
  • 4
  • 27
  • 37
  • 1
    "Its not accepted by the compiler" - this is not correct. There are 2 situations I know of which allow templated class's methods in cpps. 1) explicitly instantiating the class for the types you're going to use it with(see Desmond Hume's answer) 2) If the only place the template is used is within the cpp it's defined – David Jul 12 '12 at 13:33
  • Anyone can implement templated methods in .cpp files provided that the class the methods belong to is explicitly instantiated in that or some other .cpp file. It's even better in case of a static/dynamic library. – Desmond Hume Jul 12 '12 at 13:45
  • sorry, I wasn't clear, by implement I mean separating the header and implementation of templated class – Moataz Elmasry Jul 12 '12 at 14:48