我正试图通过模板实现信号/插槽系统,以进入模板的一些高级使用。我查找了现有的实现,并在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_;
};