14 c++ templates class operator-overloading
我想在C++中实现一个C#事件,看看我能否做到.我卡住了,我知道底部是错的,但我发现我最大的问题是......
在这种情况下,如何将()操作员重载为任何内容?我不能?我可以吗?我可以实施一个好的选择吗?Tint func(float)
#include <deque>
using namespace std;
typedef int(*MyFunc)(float);
template<class T>
class MyEvent
{
deque<T> ls;
public:
MyEvent& operator +=(T t)
{
ls.push_back(t);
return *this;
}
};
static int test(float f){return (int)f; }
int main(){
MyEvent<MyFunc> e;
e += test;
}
Run Code Online (Sandbox Code Playgroud)
Jam*_*lis 23
如果您可以使用Boost,请考虑使用Boost.Signals2,它提供信号槽/事件/观察器功能.它简单易用,非常灵活.Boost.Signals2还允许您注册任意可调用对象(如仿函数或绑定成员函数),因此它更灵活,并且它具有许多功能,可帮助您正确管理对象生存期.
如果您正在尝试自己实施它,那么您就走在了正确的轨道上.但是,您遇到了一个问题:您确实想要对每个已注册函数返回的值做什么?您只能返回一个值operator(),因此您必须决定是否要返回任何内容,或者其中一个结果,或以某种方式汇总结果.
假设我们想要忽略结果,实现它非常简单,但如果将每个参数类型作为单独的模板类型参数(或者,您可以使用Boost.TypeTraits,它允许您使用轻松剖析函数类型):
template <typename TArg0>
class MyEvent
{
typedef void(*FuncPtr)(TArg0);
typedef std::deque<FuncPtr> FuncPtrSeq;
FuncPtrSeq ls;
public:
MyEvent& operator +=(FuncPtr f)
{
ls.push_back(f);
return *this;
}
void operator()(TArg0 x)
{
for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
(*it)(x);
}
};
Run Code Online (Sandbox Code Playgroud)
这要求注册函数具有void返回类型.为了能够接受任何返回类型的函数,您可以更改FuncPtr为
typedef std::function<void(TArg0)> FuncPtr;
Run Code Online (Sandbox Code Playgroud)
(或使用boost::function或std::tr1::function如果您没有可用的C++ 0x版本).如果您确实想要对返回值执行某些操作,可以将返回类型作为另一个模板参数MyEvent.这应该是相对简单的.
通过上述实现,以下应该有效:
void test(float) { }
int main()
{
MyEvent<float> e;
e += test;
e(42);
}
Run Code Online (Sandbox Code Playgroud)
另一种允许您支持不同事件的方法,就是对函数类型使用单个类型参数,并且有多个重载operator()重载,每个重载都使用不同数量的参数.这些重载必须是模板,否则您将遇到任何与事件的实际arity不匹配的重载的编译错误.这是一个可行的例子:
template <typename TFunc>
class MyEvent
{
typedef typename std::add_pointer<TFunc>::type FuncPtr;
typedef std::deque<FuncPtr> FuncPtrSeq;
FuncPtrSeq ls;
public:
MyEvent& operator +=(FuncPtr f)
{
ls.push_back(f);
return *this;
}
template <typename TArg0>
void operator()(TArg0 a1)
{
for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
(*it)(a1);
}
template <typename TArg0, typename TArg1>
void operator()(const TArg0& a1, const TArg1& a2)
{
for (typename FuncPtrSeq::iterator it(ls.begin()); it != ls.end(); ++it)
(*it)(a1, a2);
}
};
Run Code Online (Sandbox Code Playgroud)
(我在std::add_pointer这里使用过C++ 0x,但是这个类型修饰符也可以在Boost和C++ TR1中找到;它只是使得使用函数模板更简洁,因为你可以直接使用函数类型;你不要必须使用函数指针类型.)这是一个用法示例:
void test1(float) { }
void test2(float, float) { }
int main()
{
MyEvent<void(float)> e1;
e1 += test1;
e1(42);
MyEvent<void(float, float)> e2;
e2 += test2;
e2(42, 42);
}
Run Code Online (Sandbox Code Playgroud)