c++ - C++:使用 void 作为模板参数
问题描述
我有这个最小的类来表示客户端可以订阅的事件。
该事件可以具有与之关联的数据类型,因此当它被发布者触发时,该类型的参数将被传递给客户端的回调:
template<typename Arg, typename Callback = function<void(const Arg&)>>
class Event
{
public:
Event(Callback c) : mCallback(c){}
void Trigger(const Arg& arg) {
mCallback(arg);
}
private:
Callback mCallback;
};
现在我可以创建一个Event<int>
或任何其他具体类型,但对我来说,允许“空”事件非常重要,它没有与之关联的数据:Event<void>
但遗憾的是,这不起作用:
static void FooVoid() {
cout << "Look ma, no args!" << endl;
}
static void FooInt(int a) {
cout << "int arg " << a << endl;
}
int main()
{
/* Compiles */
Event<int> eInt(&FooInt);
eInt.Trigger(42);
/* Does not compile :(
Event<void> eVoid(&FooVoid);
eVoid.Trigger();
*/
return 0;
}
有什么方法可以实现这个所需的 API?如何?
(PS 解决方案应该适用于 C++11)
解决方案
解决此问题而无需明确专门化的最快方法void
是使用参数包(在 C++11 中添加)作为模板参数而不是单一类型,并使用空参数包而不是void
. 一个参数包可以同构地保存任意数量的类型,包括 0 和 1。然后它可以用来生成正确的类型和成员函数。您基本上只需要在( link...
)的每次使用附近正确添加:Arg
#include <functional>
#include <iostream>
template<typename ... Arg>
class Event
{
public:
using Callback = std::function<void(const Arg&...)>;
Event(Callback c) : mCallback(c){}
void Trigger(const Arg& ... arg) {
mCallback(arg...);
}
private:
Callback mCallback;
};
static void FooVoid() {
std::cout << "Look ma, no args!" << std::endl;
}
static void FooInt(int a) {
std::cout << "int arg " << a << std::endl;
}
int main()
{
/* Compiles */
Event<int> eInt(&FooInt);
eInt.Trigger(42);
Event<> eVoid(&FooVoid);
eVoid.Trigger();
return 0;
}
这有一个额外的好处,您可以使用带有多个参数的回调。如果这不是可取的,您可以添加一个static_assert
来防止它:
template<typename ... Arg>
class Event
{
public:
using Callback = std::function<void(const Arg&...)>;
static_assert(sizeof...(Arg) <= 1, "Too many arguments");
Event(Callback c) : mCallback(c){}
void Trigger(const Arg& ... arg) {
mCallback(arg...);
}
private:
Callback mCallback;
};
请注意,此解决方案需要Event<>
而不是Event<void>
. Event<void>
您可以通过为该用途Event<>
(链接)添加一个简短的专业化来解决这个问题:
template<>
class Event<void> : public Event<>
{
// Inherit constructors
using Event<>::Event;
};
推荐阅读
- c++ - 如何单独遍历 QByteArray 中的字节?
- python - 有没有办法在不循环代码的情况下在 python 中导入变量?
- php - 将 PHP 正则表达式爆炸数组插入 MySQL 表
- python - 如何过滤两列上的数据框并输出累积和
- java - 如何使用 Android 中的单选按钮计算分数?
- python - Bot 无法处理与功能并行的多个请求 (discord.py)
- php - 如何改进我的 PHP 脚本以插入到多个表中?
- laravel - 将“Nova Filemanager”与“Nova TinyMCE 文本编辑器与图像”包集成
- php - 尝试获取非对象的属性“名称”如何解决此问题
- java - 添加新项目后,带有自定义适配器的 ListView 崩溃?