可变模板继承顺序和语法



我正试图通过模板实现信号/插槽系统,以进入模板的一些高级使用。我查找了现有的实现,并在https://github.com/skypjack/eventpp上找到了一个。我一直在努力理解它是如何工作的,并且几乎弄清楚了,但仍然有一些事情我无法理解,在互联网上找不到任何东西(不知道要搜索什么)。

以下是我从github repo中获取的可执行代码的最小示例,加上我自己实现的额外代码:

//Signal implementation (own code)
template <typename S>
struct Signal
{
using type = S;
};
struct KeyPressedEvent : Signal<KeyPressedEvent>
{
KeyPressedEvent(int keyCode) : keyCode_{keyCode} {}
int keyCode() {return keyCode_;}
private:
int keyCode_;
};
struct KeyReleasedEvent : Signal<KeyReleasedEvent>
{
KeyReleasedEvent(int keyCode) : keyCode_{keyCode} {}
int keyCode() {return keyCode_;}
private:
int keyCode_;
};    
//Signal Bus implementation (github repo code)
template<int S, typename... E>
struct BusBase;
template<int S, typename E, typename... O>
struct BusBase<S, E, O...> : BusBase<S, O...>
{
BusBase()
{
if(std::is_same<E, KeyPressedEvent>::value)
{
std::cout << "BusBase<S, E, O...> KeyPressedEvent" << std::endl;
}
if(std::is_same<E, KeyReleasedEvent>::value)
{
std::cout << "BusBase<S, E, O...> KeyReleasedEvent" << std::endl;
}
}
Signal<E> signal_;
};
template<int S>
struct BusBase<S>
{
BusBase()
{
std::cout << "BusBase<S>" << std::endl;
}
};
template <typename... E>
struct Bus : BusBase<sizeof...(E), E...>
{
Bus()
{
std::cout << "Bus" << std::endl;
}
};
int main(int& argc, const char* args[])
{
Bus<KeyPressedEvent, KeyReleasedEvent> eventBus;
std::cin.get();
}

下面是我运行程序时得到的输出:

BusBase<S>
BusBase<S, E, O...> KeyReleasedEvent
BusBase<S, E, O...> KeyPressedEvent
Bus

我将陈述我从实现中理解的内容。如果我说错了,请纠正我。

template<int S, typename... E>
struct BusBase;

需要从总线

展开参数包
BusBase<S, E, O...>

为总线

中的每个信号实例化
BusBase<S>

在参数包已完全展开时需要

我的问题:

1。

BusBase<S>

为什么要先实例化这个模板?我本以为它是最后(在公共汽车之前)。

2。

template<int S>
struct BusBase<S>
template<int S, typename E, typename... O>
struct BusBase<S, E, O...> : BusBase<S, O...>

为什么形参既在模板声明中又在结构声明中?

谢谢你的帮助。

为什么先实例化这个模板?我本以为它是最后(在公共汽车之前)。

构造函数调用和实例化是两码事

Bus<KeyPressedEvent, KeyReleasedEvent>继承自BusBase<2, KeyPressedEvent, KeyReleasedEvent>哪个继承自BusBase<2, KeyReleasedEvent>继承自BusBase<2>

调用顺序来自(祖父母-)父级,成员,构造函数块,所以你有输出。

为什么形参既在模板声明中又在结构体声明中?

这是部分模板特化的语法。

需要注意的是,这里不需要局部特化,可以重写为:
template<int S, typename ... Es>
struct BusBase
{
BusBase()
{
std::cout << "BusBase<S>n";
(print<Es>(), ...);
}
template <typename T>
void print() const
{
if constexpr (std::is_same<T, KeyPressedEvent>::value) {
std::cout << "BusBase<S, Es...> KeyPressedEvent" << std::endl;
} else if constexpr (std::is_same<T, KeyReleasedEvent>::value) {
std::cout << "BusBase<S, Es...> KeyReleasedEvent" << std::endl;
}
}
std::tuple<Signal<Es>...> signals_;
};