C++ 可变模板成员函数类的依赖注入

C++ 可变模板成员函数类的依赖注入,c++,dependency-injection,variadic-templates,C++,Dependency Injection,Variadic Templates,上下文: 我有一个第三方记录器类,它有一个可变的日志函数,可以获取任意的nr个参数。 在我的代码库中,有几个类需要记录信息。我希望能够通过依赖注入提供一个实例,而不是硬编码这个第三方记录器类。这样,如果我想在运行时禁用日志记录,我还可以提供一个空对象 示例代码: //third partycode class Logger{ public: template<typename ...Ts> void Log(const char * format, Ts... par

上下文: 我有一个第三方记录器类,它有一个可变的日志函数,可以获取任意的nr个参数。 在我的代码库中,有几个类需要记录信息。我希望能够通过依赖注入提供一个实例,而不是硬编码这个第三方记录器类。这样,如果我想在运行时禁用日志记录,我还可以提供一个空对象

示例代码:

//third partycode
class Logger{
public:
    template<typename ...Ts>
    void Log(const char * format, Ts... params);
};

//own code
class NullLogger{
public:
    template<typename ...Ts>
    void Log(const char * format, Ts... params); // doesn't do actual logging
};

class SomeClass{
public:
    template<typename LOGGER>
    void SetLogger(std::shared_ptr<LOGGER> logger){ m_logger = logger;}

    void SomeFunction(){
        m_logger->Log("test {0},{1}", 42, 13.37);
    }
private:
    ??? m_logger;
};
//第三方代码
类记录器{
公众:
样板
无效日志(常量字符*格式,Ts…参数);
};
//自己的代码
类空记录器{
公众:
样板
void Log(const char*format,Ts…params);//不执行实际日志记录
};
上课{
公众:
样板
void SetLogger(std::shared_ptr logger){m_logger=logger;}
void函数(){
m_logger->Log(“测试{0},{1}”,42,13.37);
}
私人:
??m_记录器;
};
问题: 我如何才能使上述代码工作

我的要求:

  • 我不想让SomeClass成为模板类
  • 我无法更改第三方记录器(我可以为自己的NullLogger选择不同的设计)
  • 我希望能够在运行时交换SomeClass使用的记录器。

  • 您将无法注入任何未设计为可注入的依赖项。也许logger是,您将尝试查看Log函数是如何实现的。 日志函数是模板函数,因此现在无法重写它:

    //第三方代码
    类记录器{
    公众:
    样板
    无效日志(常量字符*格式,Ts…参数);
    };
    
    您应该检查函数日志是如何实现的

    模板
    无效日志(常量字符*格式,Ts…参数)
    {可能它在这里调用任何虚拟_函数(格式,参数…)}
    
    如果它调用任何虚拟函数,您可以覆盖它:

    //自己的代码
    类空记录器:记录器{
    公众:
    虚函数(const char*格式,Ts…params);//重写
    };
    
    也许还有另一种方法,例如,您可以提供任何特定的流对象供记录器使用。
    因此,如果您成功地实现了上述功能,您就拥有了所有可注射的功能,否则就别无选择:

    class-SomeClass{
    公众:
    void SetLogger(std::shared_ptr logger){m_logger=logger;}
    void函数(){
    m_logger->Log(“测试{0},{1}”,42,13.37);
    }
    私人:
    std::共享_ptr m_记录器;
    };
    
    您只能对虚拟函数执行依赖项注入。因此,您可以从记录器继承NullLogger,并提供std::shared_ptr。但它不会产生效果。将调用Logger函数,因为无法将模板函数设置为虚拟。所以,如果您想要一个模板函数注入,那么您只能在模板类中进行注入。@armagedescu这确实是一个难题。如果我将某个类设置为模板类,我就不能再在运行时交换记录器。看起来这是一个合理的用例,所以我曾经(现在仍然)希望有一些我忽略的替代设计适合我的需求。@Antiro42为什么要在运行时交换记录器?这对于测试目的很有意义,在测试用例中。@armagedescu Fair point,也许在记录器设置中,在运行时交换并没有那么有用。仍然好奇是否有办法做到这一点。如果您知道参数的类型有限,情况会有所不同吗?(比如int、bool、double、string)。我可以看到您能够将一个调用分解为对某个基类/接口类上重载函数的多个调用。但是,您必须重新组合这些参数以调用派生类中的第三方记录器…@Antiro42您应该记住,在运行时没有模板。在运行时是模板实例。但模板是在编译时实例化的。这就是为什么不能在虚拟函数上创建模板。如果你真的想破解你的日志,你不应该覆盖函数日志。它将不起作用,因为您调用了基类。您应该在logger中看到函数Log调用了什么函数。如果该函数是虚拟的,则重写该函数。否则你别无选择。