C++03 3.9-10:
1
|
|
As we all knows the pointer to member may not be cast into void* (GCC is OK but it's a special case anyway), according to the standrad we can store the pointer to member to a char buffer though. Unfortunately, the size of "pointer to member" is implementation defined, so we still need some hack for different compilers.
here's a table for sizeof(pointer to member) for some compilers
(http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
Compiler Options Single Multi Virtual Unknown
MSVC 4 8 12 16
MSVC /vmg 16# 16# 16# 16
MSVC /vmg /vmm 8# 8# -- 8
Intel_IA32 4 8 12 16
Intel_IA32 /vmg /vmm 4 8 -- 8
Intel_Itanium 8 12 16 20
G++ 8 8 8 8
Comeau 8 8 8 8
DMC 4 4 4 4
BCC32 12 12 12 12
BCC32 /Vmd 4 8 12 12
WCL386 12 12 12 12
CodeWarrior 12 12 12 12
XLC 20 20 20 20
DMC small 2 2 2 2
medium 4 4 4 4
WCL small 6 6 6 6
compact 6 6 6 6
medium 8 8 8 8
large 8 8 8 8
|
the original article implement each compiler's pointer to member mechanism, which I believe is insane, it's definitely not a good way to write portable codes.here's what I'm doing (code snippet).
所以pointer to member 可以被保存在byte array 里面再被解出来.这对于做delegate很有帮助.这是我目前使用的方法.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class
Delegate
{
public
:
//per-compiler constant, or use a max enough size for all compilers
#if COMPILER == COMPILER_MSVC
static
const
size_t
MAX_POINTER2MEMBER_SIZE = 16;
#elif COMPILER == COMPILER_GNUC
static
const
size_t
MAX_POINTER2MEMBER_SIZE = 8;
#else
static
const
size_t
MAX_POINTER2MEMBER_SIZE = 20;
#endif
void
* mPtr;
char
mMemberRaw[MAX_POINTER2MEMBER_SIZE ];
//store the pointer to member to a byte buffer
template
<
typename
T>
explicit
Delegate(T* ptr,
void
(T::*func)(
void
*) )
{
assert
(
sizeof
(func) <= MAX_SIZE );
::
memset
(mMemberRaw, 0, MAX_SIZE);
::
memcpy
(mMemberRaw, &func,
sizeof
(func) );
}
};
//invoke function: extract the "pointer to member" from the byte buffer
{
...
typedef
void
(T::*TMemberFn)(
void
*);
TMemberFn TFn = NULL;
::
memcpy
(&TFn, mMemberRaw,
sizeof
(TFn) );
( ((T*)mPtr)->*TFn )( data);
}
|
there's a very efficient way to do the delegate :
http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates
他也是用模板函数,但不同的是把函数地址作为模板参数.本来打算改用这个方法的.但是唯一的缺点就是需要显式指定模板参数<>来实例化, 而构造函数只能通过TAD来套用模板参数,不能显式指定...所以他用的是一个静态模板函数来构造一个对象
1
|
delegate d = delegate::frommember<T,&T::func>( pOjb); //这样稍微有点恶心.
|
而我使用的方式虽然多了一个char[], 有一点点额外的内存开销和运行时开销,但是大多数情况下几乎可以忽略不计.
主要是可以通过Template Arugment Deduction 直接创建delegate, 比如:
1
|
Delegate d(pObj, &CLASS::function);
|
所以考虑了一下,决定暂时不用他的那种方法(用起来稍微不方便,但是效率非常高).以后看情况再考虑要不要改.
另外,作为一个C++程序猿, 个人觉得"数据绑定", "反射","代理",这些使用时尽量谨慎, 不可滥用. 除了在event/msg 和 UI/Tools的极少数地方要用以外,其他地方还是尽量不要用为好. 最近把数据绑定框架做了简单重构, 幸好用到的地方不多(主要是编辑器在用), 要不然重构就哭了. 目前还没有反射,暂时不需要, 以后需要时再加.最好是另外封装,不影响现在的代码.