Skip to content

Instantly share code, notes, and snippets.

@antcolag
Last active December 11, 2022 17:49
Show Gist options
  • Save antcolag/c2c946e51f085fbcf344e8119b736d4a to your computer and use it in GitHub Desktop.
Save antcolag/c2c946e51f085fbcf344e8119b736d4a to your computer and use it in GitHub Desktop.
Possible implementation of a dependency injection framework in C++
#include <iostream>
#include <system_error>
#include <memory>
template<typename T>
class di : public std::shared_ptr<T>
{
static std::shared_ptr<T> ptr;
public:
static void reset()
{
di<T>::ptr.reset();
}
static std::shared_ptr<T> replace(std::shared_ptr<T> ptr)
{
di<T>::ptr = ptr;
return di<T>::ptr;
}
template<typename ... args_t>
static std::shared_ptr<T> emplace(args_t && ... args)
{
return di<T>::replace(std::make_shared<T>(
std::forward<args_t>(args) ...
));
}
bool is_linked() const
{
return *this && di<T>::ptr.get() == this->get();
}
static di<T> instance() requires std::is_abstract<T>::value
{
return di<T>::ptr;
}
template<typename ... args_t>
static di<T> instance(args_t && ... args) requires (!std::is_abstract<T>::value)
{
if(!di<T>::ptr) {
di<T>::emplace(std::forward<args_t>(args) ...);
}
return di<T>::ptr;
}
template<typename ... args_t>
di(args_t && ... ptr) : std::shared_ptr<T>(std::forward<args_t>(ptr) ...)
{}
~di()
{
if(this->is_linked() && di<T>::ptr.use_count() <= 2){
di<T>::ptr.reset();
}
}
};
template<typename T>
std::shared_ptr<T> di<T>::ptr {};
// some test cases
struct logger_interface
{
virtual void log(std::string) = 0;
virtual ~logger_interface() = default;
};
struct some_service_interface
{
virtual void serve() = 0;
virtual ~some_service_interface() = default;
};
struct logger_with_id : logger_interface
{
static int counter;
int id = ++counter;
void log(std::string s) {
std::cout << id << ") " << s << std::endl;
}
};
int logger_with_id::counter = 0;
struct some_service : some_service_interface
{
di<logger_interface> logger;
some_service(
di<logger_interface> logger = di<logger_interface>::instance()
) :
logger(logger)
{}
void serve() {
logger->log("serving...");
}
};
std::error_condition app = []() {
di<logger_interface>::replace(di<logger_with_id>::emplace());
di<some_service_interface>::replace(di<some_service>::emplace());
std::cout << "running app"<< std::endl;
di<logger_interface>::instance()->log("app");
di<some_service_interface>::instance()->serve();
std::cout << std::endl;
return std::error_condition{};
}();
struct decorated_logger : logger_interface {
di<logger_interface> logger;
decorated_logger(
di<logger_interface> logger = di<logger_interface>::instance()
) :
logger(logger)
{}
void log(std::string s) {
logger->log("decorating...");
logger->log(s);
}
};
std::error_condition app_with_custom_logger_on_service = [](
di<logger_interface> logger,
di<some_service_interface> service
) {
std::cout << "running app_with_custom_logger_on_service"<< std::endl;
logger->log("app");
service->serve();
std::cout << std::endl;
return std::error_condition{};
}(
di<logger_interface>::replace(std::make_shared<logger_with_id>()),
di<some_service_interface>::replace(std::make_shared<some_service>(
std::make_shared<decorated_logger>(std::make_shared<logger_with_id>())
))
);
struct mock_logger : logger_interface {
void log(std::string) {
std::cout << "mock_logger" << std::endl;
}
};
struct mock_some_service : some_service_interface {
void serve() {
std::cout << "mock_some_service" << std::endl;
}
};
std::error_condition test = [](
di<logger_interface> logger,
di<some_service_interface> service
) {
std::cout << "running test"<< std::endl;
logger->log("app");
service->serve();
std::cout << std::endl;
return std::error_condition{};
}(
di<logger_interface>::replace(std::make_shared<mock_logger>()),
di<some_service_interface>::replace(std::make_shared<mock_some_service>())
);
std::error_condition test2 = [](
) {
std::cout << "running test2"<< std::endl;
di<logger_interface>::replace(di<logger_with_id>::emplace());
di<some_service_interface>::replace(di<some_service>::emplace());
di<logger_interface>::instance()->log("app");
di<some_service_interface>::instance()->serve();
std::cout << std::endl;
return std::error_condition{};
}();
struct my_s {
int i;
my_s(int i) : i(i){}
my_s() : i(0){}
};
int test3 = [](
) {
//di<my_s>::emplace();
std::cout << "running test3"<< std::endl;
std::cout << "!! " << di<my_s>::instance().is_linked() << " " << di<my_s>::instance().get() << std::endl;
std::cout << std::endl;
return 0;
}();
int main(){
// ...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment