Variadic 模板继承顺序和语法
Variadic template inheritance order and syntax
我正在尝试通过模板实现一个 signal/slot 系统,以了解模板的一些高级用法。我查找了现有的实现并在 https://github.com/skypjack/eventpp 找到了一个。我一直在努力理解它是如何工作的,并且几乎弄明白了,但仍然有些事情我无法理解,也无法在互联网上找到任何东西(不知道要搜索什么)。
以下是我从 github 存储库中获取的代码以及我自己实现的附加代码的可执行最小示例:
//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;
需要从 Bus
扩展参数包
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...>
为什么参数既在模板声明中又在结构声明中?
感谢您的帮助。
Why is this template instantiated first? I would have expected it to be last (before Bus).
构造函数调用和实例化是不同的东西
Bus<KeyPressedEvent, KeyReleasedEvent>
继承自 BusBase<2, KeyPressedEvent, KeyReleasedEvent>
继承自 BusBase<2, KeyReleasedEvent>
继承自 BusBase<2>
调用顺序来自 (grand-)parents,成员,构造函数块,所以你有输出。
Why are the parameters both in the template declarations and in the struct declarations?
这是 partial template specialization 的语法。
请注意,这里不需要部分特化,可以重写为:
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_;
};
我正在尝试通过模板实现一个 signal/slot 系统,以了解模板的一些高级用法。我查找了现有的实现并在 https://github.com/skypjack/eventpp 找到了一个。我一直在努力理解它是如何工作的,并且几乎弄明白了,但仍然有些事情我无法理解,也无法在互联网上找到任何东西(不知道要搜索什么)。
以下是我从 github 存储库中获取的代码以及我自己实现的附加代码的可执行最小示例:
//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;
需要从 Bus
扩展参数包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...>
为什么参数既在模板声明中又在结构声明中?
感谢您的帮助。
Why is this template instantiated first? I would have expected it to be last (before Bus).
构造函数调用和实例化是不同的东西
Bus<KeyPressedEvent, KeyReleasedEvent>
继承自 BusBase<2, KeyPressedEvent, KeyReleasedEvent>
继承自 BusBase<2, KeyReleasedEvent>
继承自 BusBase<2>
调用顺序来自 (grand-)parents,成员,构造函数块,所以你有输出。
Why are the parameters both in the template declarations and in the struct declarations?
这是 partial template specialization 的语法。
请注意,这里不需要部分特化,可以重写为:
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_;
};