两年前写这个是因为学C++11练手。而且也因为sizeof(std::function<void()>)的大小有点大,不是指针大小。所以自己写个只有指针大小的版本,不过功能就少很多。
template<typename T> class Caller;//这一句使Caller<void()>这种形式成为可能
template<typename R, typename... AL> class Caller<R(AL...)> final{
struct Callable{
virtual ~Callable(){}
virtual R Call(AL...) = 0;
virtual Callable *Clone()const = 0;
}*caller;//这就是用于管理调用对象的指针
//这个模板会根据不同的类型有不同的实例
template<typename T> class CoreCaller final : public Callable{
T caller;//T可能是 函数指针、可调用对象、lambda表达式
public:
CoreCaller(const T &caller) :caller(caller){}
R Call(AL... al)final{
return caller(std::forward<AL>(al)...);
}
//必须确保T的类型对象是可复制的,这么设计只是为了便于内存管理,我偷懒了。
Callable *Clone()const final{
return new CoreCaller(caller);
}
};
Caller(Callable *caller) :caller(caller){}
public:
template<typename T> Caller(const T &caller) :
caller(new CoreCaller<T>(caller)){
}
Caller(const Caller &r) :caller(r.caller->Clone()){}
~Caller(){ delete caller; }
R operator()(AL... al)const{
return caller->Call(std::forward<AL>(al)...);
}
Caller &operator=(const Caller &r){
if (r.caller == *this)return *this;
delete caller;
caller = r.caller->Clone();
return *this;
}
};
这样就可以这么用:
void func(){}
class C{
int operator()(int x){ return x; }
}
Caller<void()> c1(func);//函数指针
c1();
Caller<int(int)> c2(C());//可调用对象
c2(2134);
Caller<void()> c3([](){});//lambda表达式
c3();
基本的思路就是用抽象类Callable提供接口,而模板类CoreCaller根据不同的实例类型实例化。至于Clone,只是我为了让对象可以传递的一种实现,当初本来想用引用计数,那样的话Callable还要添加计数的接口函数,CoreCaller也要多很多计数实现。更重要的是T caller这种写法本身就是拷贝了传进来的对象,考虑到这点干脆就直接用Clone这种解决方案(我承认只是为了偷懒)。
如果想要根据自己的需求定制自己的可调用型智能指针,不妨参考下我的这个实现。