0

I'm using class templates together with the singleton model.

The code compiles, but I am an undefined reference linker error, on tB::getSingleton().

I've searched around on the internet and I've came a long way, but singletons in combination with a template class is not very common.

The code is as follows

A.h:
class A{

    public:

        // Constructor
        A() = default;

        // Destructor
        virtual ~A() = default;

        // Gets the singleton object
        template<class T>
        static std::shared_ptr<A>& getSingleton(){
            if (handle.get() == 0x0){
                std::shared_ptr<A> inst(new T());
                handle = std::move(inst);
            }

            return handle;
        }

    public:

        static std::shared_ptr<A> handle;

};
A_A.h:
#include <A.h>

class A_A : public A{

    public:

        // Constructor
        A_A() = default;

        // Destructor
        ~A_A(); // This is defined in the .cpp file

        static std::shared_ptr<A>& getSingleton()
        {
            if(A::handle.get() == nullptr){
                std::shared_ptr<A_A> inst(new A_A());
                A_A::handle = std::move(inst);
            }
            return A::handle;
        }

};
B.h:
template<typename A_Type>
class B{

    public:

        // Constructor
        B() = default;

        // Destructor
        virtual ~B() = default;

        /**
         * @brief Get the Singleton object
         *
         * @return B singleton instance
         */
        template<class T>
        static std::shared_ptr<B>& getSingleton(){
            if (handle.get() == 0x0){
                std::shared_ptr<B> inst(new T());
                handle = std::move(inst);
            }

            return handle;
        }


    public:
        static std::shared_ptr<B<A_Type>> handle;
};
B_B.h:
#include <A.h>
#include <B.h>

template <typename A_Type=A>
class B_B : public B<A_Type>{

    public:
    
        // Constructor
        B_B() = default;
        
        // Destructor
        ~B_B() = default;
        
        /**
         * @brief Get the Singleton object and sets the uart interface
         *
         * @return singleton instance
         */
        static std::shared_ptr<B<A_Type>>& getSingleton();
        
};
B_B.tpp:
#include <B.h>
#include <B_B.h>

template <typename A_Type>
std::shared_ptr<B<A_Type>> B<A_Type>::handle;

/**
 * @brief Get the Singleton object and sets the uart interface
 *
 * @return singleton instance
 */
template <typename A_Type>
std::shared_ptr<B<A_Type>>& B_B<A_Type>::getSingleton()
{
    if(B<A_Type>::handle.get() == nullptr){
        B<A_Type>::handle = std::move(std::static_pointer_cast<B<A_Type>>(new B_B<A_Type>()));
    }
    return B<A_Type>::handle;
}
C.h:
template<typename B_Type>
class C{

    public:

        // Constructor
        C() = default;

        // Destructor
        virtual ~C() = default;

        /**
         * @brief Get the Singleton object
         *
         * @return C singleton instance
         */
        template<class T>
        static std::shared_ptr<C>& getSingleton(){
            if (handle.get() == 0x0){
                std::shared_ptr<C> inst(new T());
                handle = std::move(inst);
            }

            return handle;
        }


    public:
        static std::shared_ptr<C<B_Type>> handle;
};
C_C.h:
#include <B.h>

template <typename B_Type=B>
class C_C : public C<B_Type>{

    public:
    
        // Constructor
        C_C() = default;
        
        // Destructor
        ~C_C() = default;
        
        /**
         * @brief Get the Singleton object and sets the uart interface
         *
         * @return singleton instance
         */
        static std::shared_ptr<C<B_Type>>& getSingleton();

        void doStuff();
        
};
C_C.tpp:
#include <B.h>
#include <B_B.h>
#include <C_C.h>

template <typename B_Type>
std::shared_ptr<C<B_Type>> C<A_Type>::handle;

/**
 * @brief Get the Singleton object and sets the uart interface
 *
 * @return singleton instance
 */
template <typename B_Type>
std::shared_ptr<C<B_Type>>& C_C<B_Type>::getSingleton()
{
    if(C<B_Type>::handle.get() == nullptr){
        C<B_Type>::handle = std::move(std::static_pointer_cast<C<B_Type>>(new C_C<B_Type>()));
    }
    return C<B_Type>::handle;
}

template <typename B_Type>
void C_C<B_Type> doStuff(){
  B_Type::getSingleton();
}
main.cpp:
#include <A.h>
#include <A_A.h>
#include <B.h>
#include <B_B.h>

using tB = B_B<A_A>;
using tC = C_C<tB>;

void main(){

  tC::getSingleton()->doStuff();

}

The compiler states the following:

error: no matching function for call to C<B<A> >::getSingleton()
tim687
  • 2,256
  • 2
  • 17
  • 28
  • [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) perhaps? – Retired Ninja Mar 15 '22 at 19:35
  • @RetiredNinja yes and no, that fixes one of my problems. I've edited the code in the question above. When calling A_Type::getSingleton() is states that it can't find an getSingleton() instance for those types. – tim687 Mar 16 '22 at 16:26
  • You most likely need `getSingleton()` – Retired Ninja Mar 16 '22 at 16:32
  • No, I want to get the singleton of SomeType. I've defined the getSingleton of SomeType. And I want to use it. – tim687 Mar 16 '22 at 17:11
  • Then why is `getSingleton()` a template if the types are defined by the class template? – Retired Ninja Mar 16 '22 at 17:14
  • How would I define the getSingleton() function outside of the class declaration, whilst still inheritting the template used by the class? – tim687 Mar 16 '22 at 17:54
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/242995/discussion-between-tim687-and-retired-ninja). – tim687 Mar 16 '22 at 18:07

0 Answers0