#include <bits/stdc++.h>
#include <memory>
#include <iostream>
 
template <typename T>
class SingletonBase {
public:
    static std::shared_ptr<T> m_Instance;
 
    SingletonBase() {
        std::cout << "Calling base constructor" << std::endl;
    }
 
    static std::shared_ptr<T> GetInstance() {
        std::cout << "Calling GetInstance" << std::endl;
 
        if (m_Instance == nullptr) {
            m_Instance = std::shared_ptr<T>(new T);
        }
 
        return m_Instance;
    }
 
    void Init() {
        if (m_Instance) {
            std::cout << "Init called" << std::endl;
        } else {
            std::cout << "Init not called" << std::endl;
        }
    }
};
 
template <typename T>
std::shared_ptr<T> SingletonBase<T>::m_Instance = nullptr;
 
class Derived : public SingletonBase<Derived> {
public:
    Derived() {
        std::cout << "Calling Derived constructor" << std::endl;
    }
};
 
class Derived2 : public SingletonBase<Derived2> {
public:
    Derived2() {
        std::cout << "Calling Derived2 constructor" << std::endl;
    }
};
 
using namespace std;
 
int main() {
    std::shared_ptr<Derived> d1; 
    d1 = Derived::GetInstance();
    d1->Init();
 
    std::shared_ptr<Derived2> d2;  
    d2 = Derived2::GetInstance();
    d2->Init();
    std::cout << " -         ------";
    std::shared_ptr<Derived2> d3;  
    d3 = Derived2::GetInstance();
    d3->Init();
    return 0;
}