我们有些时候需要存储一些函数以备后用,最常用的就是C中的Callback。。。
但是到了C++年代,函数都放到了类中,想要Callback就有些复杂了。Boost::function封装了一个模版库,它可以接受静态函数,普通函数以及仿函数,为了了解它的原理,我自己试图写一个简单的类。。。
我们先看boost中function的使用
boost::function<int(int)> func; // 能接受int(int)型的函数或仿函数
在模版参数中我们看到int(int) ,这个可能一般用户感到陌生,其实它是一个函数类型,表示返回值是int,并且有一个参数是int的函数类型。
一直以来令我感到困惑的是:int(int)仅仅是一个类型,一般而言我们如果需要用模版接受这个参数的话,可以这么用
template <class F>
class Function
问题是这样的话,所有的返回值和参数(个数)信息会全部丢失,这样在Function中的operator()就无法写出合适的调用形式。
一种方式是不用此种函数类型,而用多个模版参数。如
template <class Ret, class Param1>
class Function
此时很容易得到函数的返回值和参数(并且有些Function/Delegate库中确实是这么用的,Boost的可移植类型也是这么干的),但是这么做的话,用户可能看着不习惯。
我们来看看boost是如何做到用一个模板参数同时也可以得到函数类型的返回值和参数个数信息的。
答案就是模板偏特化
在boost中有一个根本未起作用的Function类
template<
typename Signature
>
class function;
但是它有多个偏特化的版本,其中一个如下:
template<typename R,typename P1>
class function<R(P1)>
这个模版偏特化了上述的模版,并且区分出了返回值和参数。嗯,现在我们可以做一个简单的Function看看好不好使
template <typename R, typename P1>
class Function<R(P1)>
{
typedef R (*fun)(P1);
public:
Function()
{
m_function = NULL;
}
Function(fun f)
{
m_function = f;
}
R operator()(P1 p1)
{
return m_function(p1);
}
void operator=(fun f)
{
m_function = f;
}
private:
fun m_function;
};
int PrintInt(int i)
{
printf("PrintInt=%d\n",i);
return i;
}
Function<int(int)> fun(PrintInt);
int main(int argc, char* argv[])
{
fun(20);
return 0;
}
class Function<R(P1)>
{
typedef R (*fun)(P1);
public:
Function()
{
m_function = NULL;
}
Function(fun f)
{
m_function = f;
}
R operator()(P1 p1)
{
return m_function(p1);
}
void operator=(fun f)
{
m_function = f;
}
private:
fun m_function;
};
int PrintInt(int i)
{
printf("PrintInt=%d\n",i);
return i;
}
Function<int(int)> fun(PrintInt);
int main(int argc, char* argv[])
{
fun(20);
return 0;
}
代码
template<
typename Signature
>
class Function;
template <typename R, typename P1>
class Function<R(P1)>
{
typedef R (*fun)(P1);
public:
Function()
{
m_function = NULL;
}
Function(fun f)
{
m_function = f;
}
R operator()(P1 p1)
{
return m_function(p1);
}
void operator=(fun f)
{
m_function = f;
}
private:
fun m_function;
};
int PrintInt(int i)
{
printf("PrintInt=%d\n",i);
return i;
}
Function<int(int)> fun(PrintInt);
int main(int argc, char* argv[])
{
fun(20);
return 1;
}
typename Signature
>
class Function;
template <typename R, typename P1>
class Function<R(P1)>
{
typedef R (*fun)(P1);
public:
Function()
{
m_function = NULL;
}
Function(fun f)
{
m_function = f;
}
R operator()(P1 p1)
{
return m_function(p1);
}
void operator=(fun f)
{
m_function = f;
}
private:
fun m_function;
};
int PrintInt(int i)
{
printf("PrintInt=%d\n",i);
return i;
}
Function<int(int)> fun(PrintInt);
int main(int argc, char* argv[])
{
fun(20);
return 1;
}
继续,我们想包装一个类的成员变量,boost推荐的是如下调用方式:
boost::function<int (X*, int)> f;
表示此funtion接受一个类名为X,返回值为int,参数为int的函数。。。嗯,怎么看怎么不爽。。。为啥不用类的成员变量的表达方式呢--- int (FunClass::*)(int) ,也许是很多编译器不支持?
我们看看目前主流C++编译器是否支持此种类型。(vc2008和g++ 4.1.3)偏特化如下代码:
代码
template<
typename Signature
>
class Function;
template <typename R, typename P1, class T>
class Function<R (T::*)(P1)>
{
typedef R (T::*fun)(P1);
public:
Function(T &t, fun f) : m_class(t)
{
m_function = f;
}
R operator()(P1 p1)
{
return (m_class.*m_function)(p1);
}
private:
T &m_class;
fun m_function;
};
class FunClass
{
public:
int fun(int i)
{
printf("FunClass fun %d\n",i);
return i;
}
};
int main(int argc, char* argv[])
{
FunClass funclass;
Function<int (FunClass::*)(int)> fun(funclass, &FunClass::fun);
fun(123);
return 1;
}
typename Signature
>
class Function;
template <typename R, typename P1, class T>
class Function<R (T::*)(P1)>
{
typedef R (T::*fun)(P1);
public:
Function(T &t, fun f) : m_class(t)
{
m_function = f;
}
R operator()(P1 p1)
{
return (m_class.*m_function)(p1);
}
private:
T &m_class;
fun m_function;
};
class FunClass
{
public:
int fun(int i)
{
printf("FunClass fun %d\n",i);
return i;
}
};
int main(int argc, char* argv[])
{
FunClass funclass;
Function<int (FunClass::*)(int)> fun(funclass, &FunClass::fun);
fun(123);
return 1;
}
哈哈,编译器老老实实通过了,结果也对。