如何解决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?怎么样?
(P.S 解决方案应该适用于 C++11)
解决方法
无需明确专门针对 void
解决此问题的最快方法是使用 parameter pack(在 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>
(link) 的 Event<>
添加一个简短的专业化来解决这个问题:
template<>
class Event<void> : public Event<>
{
// Inherit constructors
using Event<>::Event;
};
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。