Как передать другой параметр шаблона, когда класс шаблона использует пакет параметров? - PullRequest
1 голос
/ 05 ноября 2019

Я хотел бы создать класс шаблона, который реализует метод print() для каждого типа, передаваемого в качестве параметров шаблона.

Примерно так:

class Interface
{
public:
    virtual ~Interface() = default;
    virtual void print(int) = 0;
    virtual void print(double) = 0;
};
X x<int, double, Interface>;

class X имеет открытый метод void print() и это работает.

Весь код ниже:

#include <iostream>
#include <type_traits>

struct Printer
{
    void print(int i) {std::cout << i << std::endl; }
    void print(double d) {std::cout << d << std::endl; } 
};

class Interface
{
public:
    virtual ~Interface() = default;
    virtual void print(int) = 0;
    virtual void print(double) = 0;
};

template <typename... Args>
class X;

template <typename Interface>
class X<Interface> : public Interface
{
    static_assert(std::is_abstract<Interface>::value, "Last argument should be an interface");

public:
    X(Printer printer) {}
    using Interface::print;
};

template <typename Arg, typename... Args>
class X<Arg, Args...> : public X<Args...>
{
    using Parent = X<Args...>;

public:
    using Parent::print;

    X(Printer printer_): Parent(printer), printer{printer_} {}
    void print(Arg arg) override { printer.print(arg); }

private:
    Printer printer;
};

int main()
{
    Printer printer;
    X<double, int, Interface> x(printer);
    x.print(5);
}

Как видите, class X использует класс Printer, но проблема в том, что я хотел бы иметь Printerв качестве параметра шаблона ...

Возможно ли это? Как это сделать?

Ответы [ 2 ]

2 голосов
/ 05 ноября 2019

Как вы видите, класс X использует класс Printer, но проблема в том, что я хотел бы использовать Printer в качестве параметра шаблона ...

Возможно ли это? Как это сделать?

Извините, но ... Я не вижу проблемы (с большим упрощением, предложенным Story Teller: поместите один Printer объект в базовый случай)

template <typename...>
class X;

template <typename Printer, typename Interface>
class X<Printer, Interface> : public Interface
 {
   static_assert(std::is_abstract<Interface>::value,
                 "Last argument should be an interface");

   public:
      X (Printer p0) : printer{p0}
       { }

      using Interface::print;  // why?

   protected:
      Printer printer;
 };

template <typename Printer, typename Arg, typename... Args>
class X<Printer, Arg, Args...> : public X<Printer, Args...>
 {
   using Parent = X<Printer, Args...>;

   public:
      using Parent::print;
      using Parent::printer;

      X(Printer printer_): Parent{printer_} {}

      void print(Arg arg) override { printer.print(arg); }
 };

// ....

X<Printer, double, int, Interface> x(printer);

Не по теме: внимание: вы используете printer неинициализированный

X(Printer printer_): Parent(printer), printer{printer_} {}

Полагаю, вы должны написать Parent(printer_)

0 голосов
/ 05 ноября 2019
  • Предполагая, что требуется полиморфный интерфейс.
  • полиморфизм уменьшает значение расширения шаблона variadic
  • , сохраняя отсрочку действия для инкапсулированного принтера

Возможное решение:

#include <iostream>
#include <type_traits>

// Abstract interface
class PrintInterface
{
public:
    virtual ~PrintInterface() = default;
    virtual void print(int) = 0;
    virtual void print(double) = 0;
};

// An implmentation of PrintInterface that defers to PrinterType
template<class PrinterType>
class ImplementPrintInterface : public PrintInterface
{
public:
    ImplementPrintInterface(PrinterType printer)
    : printer_(std::move(printer))
    {}

    virtual void print(int x) override
    {
        printer_.print(x);
    }

    virtual void print(double x) override
    {
        printer_.print(x);
    }

private:

    PrinterType printer_;
};

// An implementation of a thing that prints ints and doubles.
// This happens to match PrintInterface but there is no inheritance
struct Printer
{
    void print(int i) {std::cout << i << std::endl; }
    void print(double d) {std::cout << d << std::endl; } 
};

// X *is a* PrinterInterface that *uses a* PrinterType
template <typename PrinterType>
class X : public ImplementPrintInterface<PrinterType>
{
public:
    X(PrinterType printer = PrinterType())
    : ImplementPrintInterface<PrinterType>(std::move(printer))
    {}

};

int main()
{
    Printer printer;
    X<Printer> x(printer);
    x.print(5);
}
...