元生成可变参数接口实现

时间:2020-03-30 06:25:17

标签: c++ metaprogramming variadic-templates

我已经用模板化可变参数列表定义了接口,以具有与每种类型匹配的多种方法:

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 { ... }
}

它工作正常。

但是,我还想拥有一个实现该接口的类,它也是从可变参数模板中元生成的。

我认为这样的事情应该起作用:

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 :(得分:0)

我已经弄清楚了,需要虚拟继承来匹配那些接口。

编译代码:

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;

答案 1 :(得分:0)

您是从IfaceElement继承2次。一次通过ImplElement,一次通过Iface

那是

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

每个IfaceElement将有两个相同的Ts

您可以使用虚拟继承对其进行修饰,但是为什么您需要从同一基础继承两次?

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

每个IfaceElement只会从Ts继承一次。