C++ 中delegate的实现

wingfiring 2004-11-28 09:22:42
最近需要一个C++delegate的实现,比较接近C#的delegate的用法。翻遍了boost,虽然有相近的东西,但是,始终使用起来问题多多:
function:的绑定方式倒也可以接受,成员函数调用的方式实在不爽。而且,同样的函数原型,native和member对应的function类型不同,不同class的相同原型的member function类型也不同。
signal:用起来不错,但是,一来内置了slot装置,又不便于介入干扰,二来,如何绑定一般的成员函数,不知道如何实现,只能绑定native function和functor。
bind:正是我所要的。可惜,占位符最大到3。
还有个siglib++的库,昨天才看到,为时已晚。粗略的看了一下,调用的方法,似乎也是拖泥带水。
不是我喜欢自己发明轮子,实在是迫不得已,只好自己写delegate了。手写的代码不长,贴在下面共享:

/*
copyrite: 别逗了(非典型秃子)
Description: C++的delegate实现。
可以随意复制、修改、分发、使用。不要说是自己的就可以了。^_^
*/
#ifndef DELEGATE_H
#define DELEGATE_H
#include "contract.h"//自己的一个库,只和下面的一些断言有关。
namespace nice
{
template<typename T>
class delegate;
//长长的宏,没办法:(
#define DELEGATE(TEMPLATE_ARGS, FUNCTION_ARGS, FUNCTION_PARA)\
template< typename Ret TEMPLATE_ARGS >\
class delegate<Ret (FUNCTION_ARGS)>\
{\
struct FunctionHolder\
{\
virtual Ret operator()(FUNCTION_ARGS) = 0;\
virtual FunctionHolder* clone() const = 0;\
virtual ~FunctionHolder(){};\
};\
FunctionHolder* h;\
\
template<typename Functor>\
struct FunctorHolder : public FunctionHolder\
{\
Functor* Fun;\
FunctorHolder(Functor* nfun) : Fun(nfun){}\
virtual Ret operator()(FUNCTION_ARGS)\
{\
return (*Fun)(FUNCTION_PARA);\
}\
virtual FunctionHolder* clone() const\
{\
return new FunctorHolder(*this);\
}\
};\
\
template<typename U, typename MemFun>\
struct MemHolder : public FunctionHolder\
{ \
U obj;\
MemFun memFun; \
\
MemHolder(U aObj, MemFun amfun) \
: obj(aObj), memFun(amfun){}\
\
virtual Ret operator()(FUNCTION_ARGS) \
{\
return ((*obj).*memFun)(FUNCTION_PARA);\
}\
virtual FunctionHolder* clone() const\
{\
return new MemHolder(*this);\
}\
};\
FunctionHolder* cloneHolder() const\
{\
if (connected())\
return h->clone();\
return NULL;\
}\
public:\
delegate() : h(0)\
{\
}\
~delegate() \
{ \
disconnect(); \
} \
\
template<typename Functor>\
delegate(Functor* nfun_) \
: h(new FunctorHolder<Functor>(nfun_))\
{\
}\
\
delegate(const delegate& rhs) : h(rhs.cloneHolder())\
{}\
template <typename U, typename MemFun>\
delegate(U aObj, MemFun mFun) \
: h(new MemHolder<U, MemFun>(aObj, mFun))\
{ \
}\
delegate& operator=(const delegate& rhs)\
{\
if (&rhs != this)\
{\
disconnect();\
h = rhs.cloneHolder();\
}\
return *this;\
}\
template<typename Functor>\
void connect(Functor* nfun_)\
{ \
disconnect();\
h = new FunctorHolder<Functor>(nfun_);\
}\
\
template <typename U, typename MemFun>\
void connect(U aObj, MemFun mFun)\
{\
if (h) delete h;\
h = new MemHolder<U, MemFun>(aObj, mFun);\
}\
\
void disconnect() \
{ \
if (connected()) delete h; \
h = 0; \
} \
\
bool connected() const\
{\
return (h != NULL);\
}\
\
Ret operator()(FUNCTION_ARGS)\
{\
pre_condition(connected());\
return (*h)(FUNCTION_PARA);\
}\
};
//*/

#define TEMPLATE_ARGS_0
#define FUNCTION_ARGS_0
#define FUNCTION_PARA_0

#define TEMPLATE_ARGS_1 , typename T0
#define FUNCTION_ARGS_1 T0 t0
#define FUNCTION_PARA_1 t0

/* Defines Generate code:
for (int i = 2; i <= 50; i++)
{
printf("#define TEMPLATE_ARGS_%d TEMPLATE_ARGS_%d, typename T%d\n", i, i - 1, i - 1) ;
printf("#define FUNCTION_ARGS_%d FUNCTION_ARGS_%d, T%d t%d\n", i, i - 1, i - 1, i - 1);
printf("#define FUNCTION_PARA_%d FUNCTION_PARA_%d, t%d\n\n", i, i - 1, i - 1);
};

for (int i = 0; i <= 50; ++i)
printf("DELEGATE(TEMPLATE_ARGS_%d, FUNCTION_ARGS_%d, FUNCTION_PARA_%d)\n", i, i, i);
*/

//Auto Generate code:----------------------------------------------
#define TEMPLATE_ARGS_2 TEMPLATE_ARGS_1, typename T1
#define FUNCTION_ARGS_2 FUNCTION_ARGS_1, T1 t1
#define FUNCTION_PARA_2 FUNCTION_PARA_1, t1
....

/*
$Archive: $
$Author: $
$Date: $
$Revision: $
$Header: $

Author: wingfire
Description: C++的delegate实现。
*/
#ifndef DELEGATE_H
#define DELEGATE_H
#include "contract.h"
namespace nice
{
template<typename T>
class delegate;

#define DELEGATE(TEMPLATE_ARGS, FUNCTION_ARGS, FUNCTION_PARA)\
template< typename Ret TEMPLATE_ARGS >\
class delegate<Ret (FUNCTION_ARGS)>\
{\
struct FunctionHolder\
{\
virtual Ret operator()(FUNCTION_ARGS) = 0;\
virtual FunctionHolder* clone() const = 0;\
virtual ~FunctionHolder(){};\
};\
FunctionHolder* h;\
\
template<typename Functor>\
struct FunctorHolder : public FunctionHolder\
{\
Functor* Fun;\
FunctorHolder(Functor* nfun) : Fun(nfun){}\
virtual Ret operator()(FUNCTION_ARGS)\
{\
return (*Fun)(FUNCTION_PARA);\
}\
virtual FunctionHolder* clone() const\
{\
return new FunctorHolder(*this);\
}\
};\
\
template<typename U, typename MemFun>\
struct MemHolder : public FunctionHolder\
{ \
U obj;\
MemFun memFun; \
\
MemHolder(U aObj, MemFun amfun) \
: obj(aObj), memFun(amfun){}\
\
virtual Ret operator()(FUNCTION_ARGS) \
{\
return ((*obj).*memFun)(FUNCTION_PARA);\
}\
virtual FunctionHolder* clone() const\
{\
return new MemHolder(*this);\
}\
};\
FunctionHolder* cloneHolder() const\
{\
if (connected())\
return h->clone();\
return NULL;\
}\
public:\
delegate() : h(0)\
{\
}\
~delegate() \
{ \
disconnect(); \
} \
\
template<typename Functor>\
delegate(Functor* nfun_) \
: h(new FunctorHolder<Functor>(nfun_))\
{\
}\
\
delegate(const delegate& rhs) : h(rhs.cloneHolder())\
{}\
template <typename U, typename MemFun>\
delegate(U aObj, MemFun mFun) \
: h(new MemHolder<U, MemFun>(aObj, mFun))\
{ \
}\
delegate& operator=(const delegate& rhs)\
{\
if (&rhs != this)\
{\
disconnect();\
h = rhs.cloneHolder();\
}\
return *this;\
}\
template<typename Functor>\
void connect(Functor* nfun_)\
{ \
disconnect();\
h = new FunctorHolder<Functor>(nfun_);\
}\
\
template <typename U, typename MemFun>\
void connect(U aObj, MemFun mFun)\
{\
if (h) delete h;\
h = new MemHolder<U, MemFun>(aObj, mFun);\
}\
\
void disconnect() \
{ \
if (connected()) delete h; \
h = 0; \
} \
\
bool connected() const\
{\
return (h != NULL);\
}\
\
Ret operator()(FUNCTION_ARGS)\
{\
pre_condition(connected());\
return (*h)(FUNCTION_PARA);\
}\
};
//*/

#define TEMPLATE_ARGS_0
#define FUNCTION_ARGS_0
#define FUNCTION_PARA_0

#define TEMPLATE_ARGS_1 , typename T0
#define FUNCTION_ARGS_1 T0 t0
#define FUNCTION_PARA_1 t0

/* Defines Generate code:
for (int i = 2; i <= 50; i++)
{
printf("#define TEMPLATE_ARGS_%d TEMPLATE_ARGS_%d, typename T%d\n", i, i - 1, i - 1) ;
printf("#define FUNCTION_ARGS_%d FUNCTION_ARGS_%d, T%d t%d\n", i, i - 1, i - 1, i - 1);
printf("#define FUNCTION_PARA_%d FUNCTION_PARA_%d, t%d\n\n", i, i - 1, i - 1);
};

for (int i = 0; i <= 50; ++i)
printf("DELEGATE(TEMPLATE_ARGS_%d, FUNCTION_ARGS_%d, FUNCTION_PARA_%d)\n", i, i, i);
*/

//Auto Generate code:----------------------------------------------
#define TEMPLATE_ARGS_2 TEMPLATE_ARGS_1, typename T1
#define FUNCTION_ARGS_2 FUNCTION_ARGS_1, T1 t1
#define FUNCTION_PARA_2 FUNCTION_PARA_1, t1
...全文
680 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
bluejugar 2005-03-11
  • 打赏
  • 举报
回复
看不懂.
轻轻的顶一下.
wingfiring 2004-11-29
  • 打赏
  • 举报
回复
/* Defines Generate code:
for (int i = 2; i <= 50; i++)
{
printf("#define TEMPLATE_ARGS_%d TEMPLATE_ARGS_%d, typename T%d\n", i, i - 1, i - 1) ;
printf("#define FUNCTION_ARGS_%d FUNCTION_ARGS_%d, T%d t%d\n", i, i - 1, i - 1, i - 1);
printf("#define FUNCTION_PARA_%d FUNCTION_PARA_%d, t%d\n\n", i, i - 1, i - 1);
};

for (int i = 0; i <= 50; ++i)
printf("DELEGATE(TEMPLATE_ARGS_%d, FUNCTION_ARGS_%d, FUNCTION_PARA_%d)\n", i, i, i);
*/

//Auto Generate code:----------------------------------------------
#define TEMPLATE_ARGS_2 TEMPLATE_ARGS_1, typename T1
#define FUNCTION_ARGS_2 FUNCTION_ARGS_1, T1 t1
#define FUNCTION_PARA_2 FUNCTION_PARA_1, t1
....
#define TEMPLATE_ARGS_3 TEMPLATE_ARGS_2, typename T2
#define FUNCTION_ARGS_3 FUNCTION_ARGS_2, T2 t2
#define FUNCTION_PARA_3 FUNCTION_PARA_2, t2

#define TEMPLATE_ARGS_4 TEMPLATE_ARGS_3, typename T3
#define FUNCTION_ARGS_4 FUNCTION_ARGS_3, T3 t3
#define FUNCTION_PARA_4 FUNCTION_PARA_3, t3
...

DELEGATE(TEMPLATE_ARGS_0, FUNCTION_ARGS_0, FUNCTION_PARA_0)
DELEGATE(TEMPLATE_ARGS_1, FUNCTION_ARGS_1, FUNCTION_PARA_1)
DELEGATE(TEMPLATE_ARGS_2, FUNCTION_ARGS_2, FUNCTION_PARA_2)
DELEGATE(TEMPLATE_ARGS_3, FUNCTION_ARGS_3, FUNCTION_PARA_3)
...
};
#endif//end DELEGATE_H

测试用例:
CPPUNIT_TEST_SUITE_REGISTRATION(test_delegate);
using namespace nice;

int local_add(int a, int b)
{
return a + b;
}

struct functor_add
{
int m;
int mem_add(int a, int b)
{
return a + b + m;
}
};

struct functor_mul
{
int m;
int operator()(int a, int b)
{
return (a + b) * m;
}
};


void test_delegate::testMain()
{
typedef delegate<int(int, int)> testDele2;

//默认ctor没有连接上
testDele2 dele1;
CPPUNIT_ASSERT(!dele1.connected());

//connect
testDele2 dele2(local_add);
CPPUNIT_ASSERT(dele2.connected());

//调用
CPPUNIT_ASSERT(dele2(2, 3) == 5);

//copy ctor
testDele2 dele3 = dele2;
CPPUNIT_ASSERT(dele3.connected());
CPPUNIT_ASSERT(dele3(2, 3) == 5);

//disconnect
dele2.disconnect();
CPPUNIT_ASSERT(!dele2.connected());

//test clone
CPPUNIT_ASSERT(dele3.connected());
dele3(2, 3);
CPPUNIT_ASSERT(dele3(2, 3) == 5);

//assign
dele2 = dele3;
CPPUNIT_ASSERT(dele2(2, 3) == 5);

//member function
functor_add fctor;
fctor.m = 7;
dele2.connect(&fctor, &functor_add::mem_add);
CPPUNIT_ASSERT(dele2(2, 3) == 12);

//functor
functor_mul fm;
fm.m = 3;
testDele2 dele4(&fm);
CPPUNIT_ASSERT(dele4(2, 3) == 15);
fm.m = 4;
CPPUNIT_ASSERT(dele4(2, 3) == 20);

dele2.connect(&fm);

//smart ptr
boost::shared_ptr<functor_mul> sh_ptr(new functor_mul);
(*sh_ptr).m = 10;

dele2.connect(sh_ptr);
CPPUNIT_ASSERT(dele2(2, 3) == 50);
}
wingfiring 2004-11-29
  • 打赏
  • 举报
回复
更新说明:
修改了借口,增加了对smart_ptr的支持。

最近需要一个C++delegate的实现,比较接近C#的delegate的用法。翻遍了boost,虽然有相近的东西,但是,始终使用起来问题多多:
function:的绑定方式倒也可以接受,成员函数调用的方式实在不爽。而且,同样的函数原型,native和member对应的function类型不同,不同class的相同原型的member function类型也不同。
signal:用起来不错,但是,一来内置了slot装置,又不便于介入干扰,二来,如何绑定一般的成员函数,不知道如何实现,只能绑定native function和functor。
bind:正是我所要的。可惜,占位符最大到3。
还有个siglib++的库,昨天才看到,为时已晚。粗略的看了一下,调用的方法,似乎也是拖泥带水。
不是我喜欢自己发明轮子,实在是迫不得已,只好自己写delegate了。手写的代码不长,贴在后面共享.

Deltegate的使用
一.说明:
delegate的用法和C#的有些类似,相对来说还是比较简洁的。实现上,代码并不复杂。没有怎么考虑移植性的问题。

二.使用:

1.例子

delegate<int(int, int)> dele_binary;

定义了一个委托:dele_binary, dele_binary可以持有如下形式的函数:

int navive_fun(int, int);
struct functor{
int operator()(int, int);

} a_functor;

struct A{
int mem_fun(int, int);

} an_a;

绑定delegate到实际的函数的过程:

dele_binary.connect(&native_fun); //绑定到普通函数,&运算符是可选的

dele_binary.connect(&a_functor); //绑定到仿函数,&是必须的

dele_binary.connect(&an_a, &A::mem_fun); //绑定到普通成员函数,两个&都是必须的

注意:dele_binary类型定义的模版参数是:int(int, int)的形式,不要加上*,这可以参考boost::function。这样写是符合标准的,缺点是可能移植性暂时会受到影响。



2.调用方式

delegate重载了operator(),对于上述的三种绑定过程,具有统一的调用形式:

int x = dele_binary(1,2);

delegate重载了operator()。同时,可以注意到,例子中的差别只在于connect的形式不同,dele_binary的数据类型是确定的,因此,delegate可以放入容器当中,也可以无差别的调用。此外,delegate本身也是一个functor,也可以放入另一个delegate中,一般而言,建议避免这样做。

为了方便使用,也允许在delegate的构造函数中直接连接被委托的对象,形式如下:

delegate<int(int, int)> dele_binary (&native_fun);

delegate<int(int, int)> dele_binary (&a_functor);

delegate<int(int, int)> dele_binary (&an_a, &A::mem_fun);

在通过delegate调用被委托对象之前,必须确保delegate实例已经连接到某个对象。可以通过connected方法检查,是否已经连接到确定对象。也可以通过disconnect断开和对象的连接。方法原型如下:

bool connected() const;

void disconnect();



3.Copy & assignment

delegate具有深拷贝语义。

三.实现部分

实际的实现使用了相当多的宏,并非我所愿。不过,我的使用仅仅是把宏当作最简单的字符串替换,并没有使用什么复杂的技巧,所以,阅读上应该问题不大,不想在此作冗长的讨论。欢迎讨论实现、语义上的问题。

代码部分:
/*
copywrite: 别逗了(非典型秃子)
Description: C++的delegate实现。
可以随意复制、修改、分发、使用。不要说是自己的就可以了。^_^
*/
#ifndef DELEGATE_H
#define DELEGATE_H
#include "contract.h"
namespace nice
{
template<typename T>
class delegate;

#define DELEGATE(TEMPLATE_ARGS, FUNCTION_ARGS, FUNCTION_PARA)\
template< typename Ret TEMPLATE_ARGS >\
class delegate<Ret (FUNCTION_ARGS)>\
{\
struct FunctionHolder\
{\
virtual Ret operator()(FUNCTION_ARGS) = 0;\
virtual FunctionHolder* clone() const = 0;\
virtual ~FunctionHolder(){};\
};\
FunctionHolder* h;\
\
template<typename FunctorPtr>\
struct FunctorHolder : public FunctionHolder\
{\
FunctorPtr Fun;\
FunctorHolder(FunctorPtr nfun) : Fun(nfun){}\
virtual Ret operator()(FUNCTION_ARGS)\
{\
return (*Fun)(FUNCTION_PARA);\
}\
virtual FunctionHolder* clone() const\
{\
return new FunctorHolder(*this);\
}\
};\
\
template<typename U, typename MemFun>\
struct MemHolder : public FunctionHolder\
{ \
U obj;\
MemFun memFun; \
\
MemHolder(U aObj, MemFun amfun) \
: obj(aObj), memFun(amfun){}\
\
virtual Ret operator()(FUNCTION_ARGS) \
{\
return ((*obj).*memFun)(FUNCTION_PARA);\
}\
virtual FunctionHolder* clone() const\
{\
return new MemHolder(*this);\
}\
};\
FunctionHolder* cloneHolder() const\
{\
if (connected())\
return h->clone();\
return NULL;\
}\
public:\
delegate() : h(0)\
{\
}\
~delegate() \
{ \
disconnect(); \
} \
\
template<typename FunctorPtr>\
delegate(FunctorPtr nfun_) \
: h(new FunctorHolder<FunctorPtr>(nfun_))\
{\
}\
\
delegate(const delegate& rhs) : h(rhs.cloneHolder())\
{}\
template <typename U, typename MemFun>\
delegate(U aObj, MemFun mFun) \
: h(new MemHolder<U, MemFun>(aObj, mFun))\
{ \
}\
delegate& operator=(const delegate& rhs)\
{\
if (&rhs != this)\
{\
disconnect();\
h = rhs.cloneHolder();\
}\
return *this;\
}\
template<typename FunctorPtr>\
void connect(FunctorPtr nfun_)\
{ \
disconnect();\
h = new FunctorHolder<FunctorPtr>(nfun_);\
}\
\
template <typename U, typename MemFun>\
void connect(U aObj, MemFun mFun)\
{\
if (h) delete h;\
h = new MemHolder<U, MemFun>(aObj, mFun);\
}\
\
void disconnect() \
{ \
if (connected()) delete h; \
h = 0; \
} \
\
bool connected() const\
{\
return (h != NULL);\
}\
\
Ret operator()(FUNCTION_ARGS)\
{\
pre_condition(connected());\
return (*h)(FUNCTION_PARA);\
}\
};
//*/

#define TEMPLATE_ARGS_0
#define FUNCTION_ARGS_0
#define FUNCTION_PARA_0

#define TEMPLATE_ARGS_1 , typename T0
#define FUNCTION_ARGS_1 T0 t0
#define FUNCTION_PARA_1 t0


wingfiring 2004-11-28
  • 打赏
  • 举报
回复
这个也许清楚一点。
http://blog.csdn.net/wingfiring/archive/2004/11/28/197114.aspx
socrazylee 2004-11-28
  • 打赏
  • 举报
回复
up
wingfiring 2004-11-28
  • 打赏
  • 举报
回复
测试用例:
CPPUNIT_TEST_SUITE_REGISTRATION(test_delegate);
using namespace nice;

int local_add(int a, int b)
{
return a + b;
}

struct functor_add
{
int m;
int mem_add(int a, int b)
{
return a + b + m;
}
};

struct functor_mul
{
int m;
int operator()(int a, int b)
{
return (a + b) * m;
}
};


void test_delegate::testMain()
{
typedef delegate<int(int, int)> testDele2;

//默认ctor没有连接上
testDele2 dele1;
CPPUNIT_ASSERT(!dele1.connected());

//connect
testDele2 dele2(local_add);
CPPUNIT_ASSERT(dele2.connected());

//调用
CPPUNIT_ASSERT(dele2(2, 3) == 5);

//copy ctor
testDele2 dele3 = dele2;
CPPUNIT_ASSERT(dele3.connected());
CPPUNIT_ASSERT(dele3(2, 3) == 5);

//disconnect
dele2.disconnect();
CPPUNIT_ASSERT(!dele2.connected());

//test clone
CPPUNIT_ASSERT(dele3.connected());
dele3(2, 3);
CPPUNIT_ASSERT(dele3(2, 3) == 5);

//assign
dele2 = dele3;
CPPUNIT_ASSERT(dele2(2, 3) == 5);

//member function
functor_add fctor;
fctor.m = 7;
dele2.connect(&fctor, &functor_add::mem_add);
CPPUNIT_ASSERT(dele2(2, 3) == 12);

//functor
functor_mul fm;
fm.m = 3;
testDele2 dele4(&fm);
CPPUNIT_ASSERT(dele4(2, 3) == 15);
fm.m = 4;
CPPUNIT_ASSERT(dele4(2, 3) == 20);

dele2.connect(&fm);
}
wingfiring 2004-11-28
  • 打赏
  • 举报
回复
//续:

#define TEMPLATE_ARGS_3 TEMPLATE_ARGS_2, typename T2
#define FUNCTION_ARGS_3 FUNCTION_ARGS_2, T2 t2
#define FUNCTION_PARA_3 FUNCTION_PARA_2, t2

#define TEMPLATE_ARGS_4 TEMPLATE_ARGS_3, typename T3
#define FUNCTION_ARGS_4 FUNCTION_ARGS_3, T3 t3
#define FUNCTION_PARA_4 FUNCTION_PARA_3, t3
...

DELEGATE(TEMPLATE_ARGS_0, FUNCTION_ARGS_0, FUNCTION_PARA_0)
DELEGATE(TEMPLATE_ARGS_1, FUNCTION_ARGS_1, FUNCTION_PARA_1)
DELEGATE(TEMPLATE_ARGS_2, FUNCTION_ARGS_2, FUNCTION_PARA_2)
DELEGATE(TEMPLATE_ARGS_3, FUNCTION_ARGS_3, FUNCTION_PARA_3)
...
};
#endif//end DELEGATE_H

上面的贴得有点问题,重复了好几遍,该死!
有用的就是前面150多行就结束了。
后面的是我不小心多按了ctrl-v

5,530

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 模式及实现
社区管理员
  • 模式及实现社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧