2009年11月11日 星期三

C++ TR1 Function實做簡易版

C++ Technical Report 1 (TR1) 是 C++ Standard Template Library的追加項目。TR1自己並非標準,他是一份草稿文件。然而他所提出的項目很有可能成為下次的官方標準。

其中最引人注目的就是Smart Pointer、Polymorphic function wrapper以及Function Object Binder三項。這三項主要都是來自boost這個Library。此次介紹Polymorphic function wrapper,也就是boost::function。

由於C++ 0x才支援Variadic templates語法,想支援不定參數,變成C++98最大的困難點,不同的Library有不同的做法,Loki是使用TypeList技巧。這邊用的只是簡單的Marco。

Function.h

#ifndef _Function_H_
#define _Function_H_

#define Parameters 0
#define FUNCTION_PARAMS // T1 p1, T2 p2
#define TEMPLATE_PARAMS // typename T1, typename T2
#define TEMPLATE_ARGS //T1
#define FUNCTION_ARGS // p1, p2
#include "functor.h"

#undef Parameters
#undef FUNCTION_PARAMS
#undef TEMPLATE_PARAMS
#undef TEMPLATE_ARGS
#undef FUNCTION_ARGS


#define Parameters 1
#define FUNCTION_PARAMS T1 p1
#define TEMPLATE_PARAMS typename T1
#define TEMPLATE_ARGS T1
#define FUNCTION_ARGS p1
#include "functor.h"

#undef Parameters
#undef FUNCTION_PARAMS
#undef TEMPLATE_PARAMS
#undef TEMPLATE_ARGS
#undef FUNCTION_ARGS

#endif


目前為止,可以吃下零至五個參數,需要的話可繼續擴充。看起來沒什麼技巧可言,重複定義Marco,然後重複include同一個檔案,而所有的奧妙都在底下。



Functor.h



#if Parameters == 0
#define COMMA
#else
#define COMMA ,
#endif

#define Concate(X, Y) _Concate(X, Y)
#define _Concate(X, Y) X##Y

template <typename> class Function;

template <typename R COMMA TEMPLATE_PARAMS>
class Concate(FunctionBase, Parameters)
{
public:
virtual ~Concate(FunctionBase, Parameters)() {}
virtual R operator()(FUNCTION_PARAMS) = 0;
};
template <typename R COMMA TEMPLATE_PARAMS, typename TFunctor>
class Concate(StaticFunctionImpl, Parameters) :
public Concate(FunctionBase, Parameters)<R COMMA TEMPLATE_ARGS>
{
TFunctor m_Func;
public:
Concate(StaticFunctionImpl, Parameters)(TFunctor rFunc) : m_Func(rFunc) {}
R operator()(FUNCTION_PARAMS) { return m_Func(FUNCTION_ARGS); }
};
template <typename R COMMA TEMPLATE_PARAMS, typename T>
class Concate(MemberFunctionImpl, Parameters) :
public Concate(FunctionBase, Parameters)<R COMMA TEMPLATE_ARGS>
{
T *m_obj;
typedef R (T::*MemberFunction)(FUNCTION_PARAMS);
typedef R (T::*MemberFunctionConst)(FUNCTION_PARAMS) const;
union
{
MemberFunction m_Func;
MemberFunctionConst m_Func2;
};
public:
Concate(MemberFunctionImpl, Parameters)(T *pobj, MemberFunction pFunc) :
m_obj(pobj), m_Func(pFunc) {}
Concate(MemberFunctionImpl, Parameters)(T *pobj, MemberFunctionConst pFunc) :
m_obj(pobj), m_Func2(pFunc) {}
R operator()(FUNCTION_PARAMS) { return (m_obj->*m_Func)(FUNCTION_ARGS); }
R operator()(FUNCTION_PARAMS) const { return (m_obj->*m_Func2)(FUNCTION_ARGS); }
};
template <typename R COMMA TEMPLATE_PARAMS>
class Function<R (TEMPLATE_ARGS)>
{
Concate(FunctionBase, Parameters)<R COMMA TEMPLATE_ARGS> *m_pImpl;
void _release()
{
if (m_pImpl)
{
delete m_pImpl;
m_pImpl = NULL;
}
}
public:
Function() : m_pImpl(NULL) {}
template <typename TFunctor>
Function(TFunctor pFunc) :
m_pImpl(new Concate(StaticFunctionImpl, Parameters)<R COMMA TEMPLATE_ARGS, TFunctor>(pFunc)) {}
template <typename T COMMA TEMPLATE_PARAMS>
Function(T *obj, R (T::*pFunc)(FUNCTION_PARAMS)) :
m_pImpl(new Concate(MemberFunctionImpl, Parameters)<R COMMA TEMPLATE_ARGS, T>(obj, pFunc)) {}
template <typename T COMMA TEMPLATE_PARAMS>
Function(T *obj, R (T::*pFunc)(FUNCTION_PARAMS) const) :
m_pImpl(new Concate(MemberFunctionImpl, Parameters)<R COMMA TEMPLATE_ARGS, T>(obj, pFunc)) {}
~Function() { _release(); }
R operator()(FUNCTION_PARAMS) { return (*m_pImpl)(FUNCTION_ARGS); }
R operator()(FUNCTION_PARAMS) const { return (*m_pImpl)(FUNCTION_ARGS); }
};

#undef Concate
#undef COMMA




用到的技巧嘛,大概就是Template Partial Specialization



Demo Program



#include <iostream>
#include "function.h"
void print_1()
{
std::cout << 1 << std::endl;
}
struct print_vplus3
{
void operator()(int v)
{
std::cout << v + 3 << std::endl;
}
};

int main()
{
Function<void ()> func(print_1);
func();
print_vplus3 b;
Function<void (int)> func3(b);
func3(1);
}


雖然不鼓勵自己重新打造輪胎,不過也只有動手做過一次,才能熟練技巧。

1 則留言:

 

我們搬家了

新部落格在http://b-plurkers.com/