goost::function 其實也沒什麼,主要的關鍵在要怎麼把函數的 type 分離出來,比如 goost::function<char(float,int)> 中的 char(float,int) 是一個 type,要怎麼分離出 char、float 和 int 這三個 type?goost::function 是借用特製化 class 自動匹配 type 的技巧,以下用例子說明:
#include <iostream>
using namespace std;
// 本尊,用來限定 template 參數只能有一個
// K 是為了指示函數型別用的,比如 int(int)
template<typename K>
class A
{
public:
A(){}
~A(){}
};
// 特製化類別
// template 參數的型別會依使用端的指定而自動匹配
template<typename K, typename T>
class A<K(T)>
{
T m_i;
public:
A(){}
~A(){}
K operator()(T i)
{
m_i = i;
cout << "K(T)" << endl;
return m_i;
}
};
// 特製化類別
template<typename K, typename T, typename S>
class A<K(T,S)>
{
float m_i;
public:
A(){}
~A(){}
K operator()(T i, S s)
{
m_i = i;
cout << "K(T,S)" << endl;
return m_i;
}
};
int main()
{
A<int(int)> a2;
A<int(long,char)> a3;
a2(2);
a3(2,2);
cout << "Hello world!" << endl;
return 0;
}
有了以上的了解,再來就直接來看如何用暴力法來實作和 goost::function 相同的功能
/*---------------------------------------------
DELEGATE.HPP v1.0
Copyright 楊志賢 CxxlMan, 2014
All Rights Reserved
可代理一般函數指標或成員函數指標,參數最多 10 個
----------------------------------------------*/
#if !defined(__DELEGATE_HPP_CxxlMan)
#define __DELEGATE_HPP_CxxlMan
namespace CxxlMan
{
// 本尊
template<typename T>
class delegate
{
public:
// Constructor
delegate(){}
// Destructor
~delegate(){}
};
} /* namespace CxxlMan */
// 產生 11 個 delegate 特製化類別
#define FUNCTION_ARGS 0
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 1
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 2
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 3
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 4
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 5
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 6
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 7
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 8
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 9
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#define FUNCTION_ARGS 10
#include "DELEGATE_TEMPLATE.HPP"
#undef FUNCTION_ARGS
#endif
/*------------------------------------------------------------------------
DELEGATE_TEMPLATE.HPP v1.0
Copyright 楊志賢 CxxlMan, 2014
All Rights Reserved
給 DELEGATE.HPP 多次引用,以建立 11 個 delegate 的特製化類別
------------------------------------------------------------------------*/
namespace CxxlMan
{
#if FUNCTION_ARGS == 0
# define FUNCTION_TEMPLATE_PARMS typename T0
# define FUNCTION_PARTIAL_SPEC T0()
# define FUNCTION_PARMS
# define FUNCTION_ARGS_VALUE
#elif FUNCTION_ARGS == 1
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1
# define FUNCTION_PARTIAL_SPEC T0(T1)
# define FUNCTION_PARMS T1 a1
# define FUNCTION_ARGS_VALUE a1
#elif FUNCTION_ARGS == 2
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1,typename T2
# define FUNCTION_PARTIAL_SPEC T0(T1,T2)
# define FUNCTION_PARMS T1 a1,T2 a2
# define FUNCTION_ARGS_VALUE a1,a2
#elif FUNCTION_ARGS == 3
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1,typename T2,typename T3
# define FUNCTION_PARTIAL_SPEC T0(T1,T2,T3)
# define FUNCTION_PARMS T1 a1,T2 a2,T3 a3
# define FUNCTION_ARGS_VALUE a1,a2,a3
#elif FUNCTION_ARGS == 4
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1,typename T2,typename T3,typename T4
# define FUNCTION_PARTIAL_SPEC T0(T1,T2,T3,T4)
# define FUNCTION_PARMS T1 a1,T2 a2,T3 a3,T4 a4
# define FUNCTION_ARGS_VALUE a1,a2,a3,a4
#elif FUNCTION_ARGS == 5
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1,typename T2,typename T3,typename T4,typename T5
# define FUNCTION_PARTIAL_SPEC T0(T1,T2,T3,T4,T5)
# define FUNCTION_PARMS T1 a1,T2 a2,T3 a3,T4 a4,T5 a5
# define FUNCTION_ARGS_VALUE a1,a2,a3,a4,a5
#elif FUNCTION_ARGS == 6
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6
# define FUNCTION_PARTIAL_SPEC T0(T1,T2,T3,T4,T5,T6)
# define FUNCTION_PARMS T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6
# define FUNCTION_ARGS_VALUE a1,a2,a3,a4,a5,a6
#elif FUNCTION_ARGS == 7
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7
# define FUNCTION_PARTIAL_SPEC T0(T1,T2,T3,T4,T5,T6,T7)
# define FUNCTION_PARMS T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7
# define FUNCTION_ARGS_VALUE a1,a2,a3,a4,a5,a6,a7
#elif FUNCTION_ARGS == 8
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8
# define FUNCTION_PARTIAL_SPEC T0(T1,T2,T3,T4,T5,T6,T7,T8)
# define FUNCTION_PARMS T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8
# define FUNCTION_ARGS_VALUE a1,a2,a3,a4,a5,a6,a7,a8
#elif FUNCTION_ARGS == 9
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9
# define FUNCTION_PARTIAL_SPEC T0(T1,T2,T3,T4,T5,T6,T7,T8,T9)
# define FUNCTION_PARMS T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8,T9 a9
# define FUNCTION_ARGS_VALUE a1,a2,a3,a4,a5,a6,a7,a8,a9
#elif FUNCTION_ARGS == 10
# define FUNCTION_TEMPLATE_PARMS typename T0,typename T1,typename T2,typename T3,typename T4,typename T5,typename T6,typename T7,typename T8,typename T9,typename T10
# define FUNCTION_PARTIAL_SPEC T0(T1,T2,T3,T4,T5,T6,T7,T8,T9,T10)
# define FUNCTION_PARMS T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8,T9 a9,T10 a10
# define FUNCTION_ARGS_VALUE a1,a2,a3,a4,a5,a6,a7,a8,a9,a10
#endif
// 特製化
template<FUNCTION_TEMPLATE_PARMS>
class delegate<FUNCTION_PARTIAL_SPEC>
{
// 函數指標的版本
class HostBase
{
T0 (*m_pFunc_Ptr)(FUNCTION_PARMS);
public:
// Constructor
HostBase(){}
// Constructor
HostBase(T0 (*pFunc_Ptr)(FUNCTION_PARMS))
{
m_pFunc_Ptr = pFunc_Ptr;
}
// Destructor
virtual ~HostBase() {}
virtual T0 Function(FUNCTION_PARMS)
{
return m_pFunc_Ptr(FUNCTION_ARGS_VALUE);
}
};
// 成員函數指標的版本
template<typename K>
class HostDerived:public HostBase
{
K &m_Obj;
T0 (K::*m_pmFunc_Ptr)(FUNCTION_PARMS);
public:
// Constructor
HostDerived(K &Obj, T0 (K::*pmFunc_Ptr)(FUNCTION_PARMS))
:m_Obj(Obj)
{
m_pmFunc_Ptr = pmFunc_Ptr;
}
// Destructor
virtual ~HostDerived() {}
T0 Function(FUNCTION_PARMS)
{
return (m_Obj.*m_pmFunc_Ptr)(FUNCTION_ARGS_VALUE);
}
};
HostBase *m_pHostBase;
public:
// Constructor
delegate()
{
m_pHostBase = NULL;
}
// Destructor
~delegate()
{
if(m_pHostBase)
delete m_pHostBase;
}
void bind(T0 (*pFunc_Ptr)(FUNCTION_PARMS))
{
if(m_pHostBase)
delete m_pHostBase;
m_pHostBase = new HostBase(pFunc_Ptr);
}
template<typename K>
void bind(K &Obj, T0 (K::*pmFunc_Ptr)(FUNCTION_PARMS))
{
if(m_pHostBase)
delete m_pHostBase;
m_pHostBase = new HostDerived<K>(Obj,pmFunc_Ptr);
}
T0 operator()(FUNCTION_PARMS)
{
if(m_pHostBase == NULL)
throw "須先使用 delegate::bind()"; // 我是很不喜歡用 throw,可是也想不出其他辦法
return m_pHostBase->Function(FUNCTION_ARGS_VALUE);
}
};
#undef FUNCTION_TEMPLATE_PARMS
#undef FUNCTION_PARTIAL_SPEC
#undef FUNCTION_PARMS
#undef FUNCTION_ARGS_VALUE
} /* namespace CxxlMan */
以下是測試程式
#include <iostream>
#include <C:\delegate\DELEGATE.HPP>
using namespace std;
using namespace CxxlMan;
int SubFunc(int lhs, int rhs)
{
return lhs - rhs;
}
struct tagAdd
{
int AddFunc(int lhs, int rhs)
{
return lhs + rhs;
}
}AddObj;
int main()
{
delegate<int(int,int)> Sub;
delegate<int(int,int)> Add;
Sub.bind(SubFunc);
Add.bind(AddObj,&tagAdd::AddFunc);
cout << "5-3 = " << Sub(5,3) << endl;
cout << "5+3 = " << Add(5,3) << endl;
return 0;
}
delegate 原碼下載:
https://www.dropbox.com/s/u8lfos941jz3hm5/delegate%20v1.0.7z
http://pan.baidu.com/s/1o6FKHUM
沒有留言:
張貼留言