Skip to content

Instantly share code, notes, and snippets.

@DieTime
Created August 23, 2023 11:53
Show Gist options
  • Save DieTime/f367355ca18d59b69c85996ea9b01c89 to your computer and use it in GitHub Desktop.
Save DieTime/f367355ca18d59b69c85996ea9b01c89 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <memory>
#include <mutex>
#include <type_traits>
namespace utils {
template <typename T, typename Interface>
struct singleton : public Interface
{
static std::shared_ptr<Interface> instance()
{
std::lock_guard guard(m_mutex);
if (!m_instance) {
if constexpr (std::is_default_constructible<T>::value) {
m_instance = std::make_shared<T>();
} else {
throw std::runtime_error(
std::string(__PRETTY_FUNCTION__) +
std::string(" attempt to use not initialized singleton class, please use") +
std::string(" initialize() before first use")
);
}
}
return m_instance;
}
template <typename ...Args>
static void initialize(Args... args)
{
std::lock_guard guard(m_mutex);
m_instance = std::make_shared<T>(args...);
}
template <typename U, typename ...Args>
static void mock(Args... args)
{
std::lock_guard guard(m_mutex);
m_instance = std::make_shared<U>(args...);
}
protected:
singleton() = default;
~singleton() = default;
singleton(const singleton&) = delete;
singleton& operator=(const singleton&) = delete;
singleton(singleton&&) = delete;
singleton& operator=(singleton&&) = delete;
private:
static inline std::mutex m_mutex;
static inline std::shared_ptr<Interface> m_instance = nullptr;
};
} /* namespace utils */
struct interface
{
virtual void send() = 0;
};
struct sender : public utils::singleton<sender, interface>
{
void send() override
{
std::cout << "sender" << std::endl;
}
};
struct mock : public interface
{
void send() override
{
std::cout << "mock" << std::endl;
}
};
int main() {
/**
* If the singleton class does not have a default constructor
* or you need to initialize the singleton with specific
* arguments, you must explicitly initialize it.
*
* sender::initialize(...)
*
*/
sender::instance()->send();
/*
* Mock a singleton if you need to with a class that
* inherits from the base singleton class.
*/
sender::mock<mock>();
sender::instance()->send();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment