c++ - 为什么模板参数推导不适用于仅指定前两个参数的可变参数模板类?

标签 c++ class templates variadic

我有一个可变参数模板类,它采用两个固定模板参数和一个可变参数列表。 当我创建一个实例时,我想指定前两个参数,然后从传递给构造函数的参数中推导出其余参数。 但它不起作用,可变参数部分似乎总是空的。当我指定所有类型(包括 ctor 参数)时,我只能创建一个实例。

这是我用来测试的代码:

#include <iostream>
#include <tuple>
#include <string>

class Service
{
public:
  virtual void Serve() = 0;
};


class InterfaceA : public Service {};
class InterfaceB : public Service {};
class InterfaceC : public Service {};


class ImplementationA : public InterfaceA
{
  virtual void Serve() override
  {
    std::cout << "Implementation A: <null>";
  }
};


class ImplementationB : public InterfaceB
{
public:
  ImplementationB(int x)
    : m_x(x)
  {}

  virtual void Serve() override
  {
    std::cout << "Implementation B: " << std::to_string(m_x);
  }

private:
  int m_x = 0;
};


class ImplementationC : public InterfaceC
{
public:
  ImplementationC(std::string str)
    : m_str(str)
  {}

  virtual void Serve() override
  {
    std::cout << "Implementation C: " << m_str;
  }

private:
  std::string m_str;
};


template <typename Interface, typename Implementation, typename... CtorArgs>
class Wrapper
{
public:
  Wrapper(CtorArgs&&... args)
    : m_ctorArgs(std::make_tuple(std::forward<CtorArgs>(args)...))
  {}

  Service& GetService()
  {
    m_service = std::apply([](CtorArgs ... ctorArgs)
    {
      return std::make_unique<Implementation>(ctorArgs...);
    },
      m_ctorArgs);

    return *m_service;
  }

private:
  std::tuple<CtorArgs ...> m_ctorArgs;
  std::unique_ptr<Service> m_service;
};

// deduction guide, not working...
template <typename Interface, typename  Implementation, typename... CtorArgs>
Wrapper(int x)->Wrapper<Interface, Implementation, int>;


int main()
{
    Wrapper<InterfaceA, ImplementationA> wrapperA;
    wrapperA.GetService().Serve();
    std::cout << "\n";

//    Wrapper<InterfaceB, ImplementationB> wrapperB(7);       // NOT OK
    Wrapper<InterfaceB, ImplementationB, int> wrapperB(7);    // OK
    wrapperB.GetService().Serve();
    std::cout << "\n";
}

我想指定服务,但在需要时按需创建它们(由于服务之间的依赖性)。我已经在生产代码中使用了工厂方法(包装器知道要传递给服务 ctor 的参数),但是在测试代码中,我希望能够快速为模拟和虚拟服务创建包装器,这可能需要与生产不同的参数服务。

我也试过指定推导指南,但是好像没有效果。。。

最佳答案

您可以使用模板构造函数,并将 std::function 作为工厂:

template <typename Interface, typename Implementation>
class Wrapper
{
public:
  template <typename... CtorArgs>
  Wrapper(CtorArgs&&... args)
    : m_factory([=](){return std::make_unique<Implementation>(ctorArgs...);})
  {}

  Service& GetService()
  {
    m_service = m_factory();
    return *m_service;
  }

private:
  std::function<std::unique_ptr<Service>()> m_factory;
  std::unique_ptr<Service> m_service;
};

推导指南没有用,因为它应该用于推导所有参数。

提供模板参数是全有还是全无。

但是你可以这样做:

Wrapper<InterfaceB, ImplementationB> wrapperB(7); // Ok

关于c++ - 为什么模板参数推导不适用于仅指定前两个参数的可变参数模板类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61893948/

相关文章:

C++ 模板化主题观察者继承/转换冲突

c++ - 如果你只有一把锤子……或者

c# - WPF。双态元素

c++ - 从 C++ 对象调用的回调函数 "C style"

c++ - 在条件中更改对象类型

xml - 将模型类转换为 XML

list - 尝试填写类(class)列表

C++ 类继承顺序

c++ - 通过推导强制引用模板类型

javascript - 模板缓存 ExpressJS