Created
August 23, 2023 11:53
-
-
Save DieTime/f367355ca18d59b69c85996ea9b01c89 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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