Реализация интерфейса с мета-генерируемыми переменными c - PullRequest
0 голосов
/ 30 марта 2020

У меня есть интерфейс, определенный с помощью списка шаблонных переменных c, чтобы иметь несколько методов, соответствующих каждому типу:

template <typename T> struct IfaceElement { virtual void m(const T &) = 0; };
template <typename... Ts> struct Iface : IfaceElement<Ts>... {};

Что я хотел бы добиться, это иметь интерфейс для другого числа Event объект. Что-то вроде:

struct A {};
struct B {};
struct Handler : Iface<A, B> {
    void m(const A &) override { ... }
    void m(const B &) override { ... }
}

, и он отлично работает.

Однако я также хотел бы иметь класс, который реализует этот интерфейс, и он также мета-генерируется из шаблона variadi c .

Я думал, что что-то вроде этого должно работать:

template <typename T> struct IfaceElement { virtual void m(const T &) = 0; };
template <typename... Ts> struct Iface : IfaceElement<Ts>... {};

template <typename T> struct ImplElement : IfaceElement<T> {
    void m(const T &) override {}
};
template <typename... Ts> struct Impl : Iface<Ts...>, ImplElement<Ts>... {};

struct Z {};
struct X {};

Impl<Z, X> q;

Но у меня есть ошибка компилятора:

test.cpp:121:12: error: cannot declare variable 'q' to be of abstract type 'Impl<Z, X>'
  121 | Impl<Z, X> q;
      |            ^
test.cpp:116:34: note:   because the following virtual functions are pure within 'Impl<Z, X>':
  116 | template <typename... Ts> struct Impl : Iface<Ts...>, ImplElement<Ts>... {};
      |                                  ^~~~
test.cpp:110:58: note:  'void IfaceElement<T>::m(const T&) [with T = X]'
  110 | template <typename T> struct IfaceElement { virtual void m(const T &) = 0; };
      |                                                          ^
test.cpp:110:58: note:  'void IfaceElement<T>::m(const T&) [with T = Z]'

Кажется, что моя реализация из ImplElement не соответствует IfaceElement чистый метод.

Есть идеи, как мне решить эту проблему?

Ответы [ 2 ]

0 голосов
/ 30 марта 2020

Вы наследуете от IfaceElement 2 раза. Один раз через ImplElement и один раз через Iface.

Это означает, что

template <typename... Ts> struct Impl : Iface<Ts...>, ImplElement<Ts>... {};

будет иметь два одинаковых IfaceElement s для каждого Ts.

You может справиться с этим с помощью виртуального наследования, но зачем вам дважды наследовать от одной и той же базы?

template <typename... Ts> struct Impl : ImplElement<Ts>... {};

Также будет работать и наследовать от IfaceElement только один раз за Ts.

0 голосов
/ 30 марта 2020

Я понял, виртуальное наследование необходимо для соответствия этим интерфейсам.

Код компиляции:

template <typename T> struct IfaceElement { virtual void m(const T &) = 0; };
template <typename... Ts> struct Iface : virtual IfaceElement<Ts>... {};

template <typename T> struct ImplElement : virtual IfaceElement<T> {
    void m(const T &) override {}
};
template <typename... Ts> struct Impl : Iface<Ts...>, ImplElement<Ts>... {};

struct Z {};
struct X {};

Impl<Z, X> q;
...