手把手教你实现一个function模板

1.实现function需要用到的相关技术

建议看本文之前,需要先了解C++11 function或者boost::function模板的基本用法,也最好看一下我的另外一篇文章:
c++11 function模板:模板特化与可变参数函数模板

如果你使用过C++11 function模板或者boost :: function, 你一定会惊讶于这个模板对函数回调带来的方便,可能也会好奇这个功能到底是怎么实现的。我觉得还是有必要研究一下背后的实现原理,因为这背后的实现用到了很多C++语言编程骚操作(语言特性和技巧)。主要体现在如下几个方面:

  • 函数对象(仿函数)
  • 虚函数与多态
  • 模板技术
  • 函数重载
  • 不定模板参数

2.function实现

2.1 公共接口的实现

实现一个抽象基类,作为调用的接口,然后从这个积累派生出几个不同的子类,从而实现对不同形式的调用。考虑到调用的函数的参数是不确定的,因此采用了不定模板参数。

// 模板参数R 表示函数的返回值类型
// 模板参数Arg 表示函数的入参类型
template <typename R, typename... Arg> 
class invoker_base {
public:
  virtual R operator()(Arg... arg)=0;
};

2.2 实现对普通函数的调用

template <typename R, typename... Arg> 
class function_ptr_invoker 
  : public invoker_base<R,Arg...> {
    typedef R (*funcType)(Arg...);
    funcType func_;
public:
    function_ptr_invoker(funcType func):func_(func) {}
    // 重写基类的调用接口,用于对普通函数的调用
    R operator()(Arg... arg) {
        return (func_)(arg...);
    }
};

2.3 实现对函数对象的调用

// 处理函数对象的版本
template <typename R, typename Arg, typename T> 
class function_object_invoker : 
  public invoker_base<R,Arg> {
    T t_;
public:
    function_object_invoker(T t):t_(t) {}
	// 重写基类的调用接口,用于对函数对象调用
    R operator()(Arg arg) {
        return t_(arg);
    }
};

2.4 实现对成员函数的调用

// 实现对类成员函数的调用
template <typename R, typename T, typename... Arg> 
class member_ptr_invoker : 
    public invoker_base<R,Arg...> {
    typedef R (T::*memfuncType)(Arg...);
    memfuncType func_;
    T* t_;
public:
    member_ptr_invoker(memfuncType func,T* t)
        :func_(func),t_(t) {}
	// 重写基类的调用接口,用于对类成员函数的调用
    R operator()(Arg... arg) {
        return (t_->*func_)(arg...);
    }
};

2.5 对不同类型函数调用的测试

到目前为止,通过虚函数,实现了对普通函数、函数对象以及类成员函数的统一调用接口了,可以通过如下方法实现对不同类型的统一调用:

// 根据pBase指向的对象的不同,调用不同的函数。
// pBase可以指向保存普通函数的对象、保存类成员函数的对象或
// 保存函数对象的对象。
pBase->operator()("hello");

完整代码如下:

#include <iostream>
#include <functional>
using namespace std;

// 实现一个抽象基类,作为调用的接口,然后从这个积累派生出几个不同的子类,从而实现对不同形式的调用
template <typename R, typename... Arg> class invoker_base {
public:
    virtual R operator()(Arg... arg)=0;
};

template <typename R, typename... Arg> class function_ptr_invoker 
  : public invoker_base<R,Arg...> {
    typedef R (*funcType)(Arg...);
    funcType func_;
public:
    
    function_ptr_invoker(funcType func):func_(func) {}

    R operator()(Arg... arg) {
        return (func_)(arg...);
    }
};
// 处理函数对象的版本
template <typename R, typename T, typename... Arg> 
class function_object_invoker : 
  public invoker_base<R,Arg...> {
    T t_;
public:
    function_object_invoker(T t):t_(t) {}

    R operator()(Arg... arg) {
        return t_(arg...);
    }
};

// 实现对类成员函数的调用
template <typename R, typename T, typename... Arg> 
class member_ptr_invoker : 
    public invoker_base<R,Arg...> {
    typedef R (T::*memfuncType)(Arg...);
    memfuncType func_;
    T* t_;
public:
    member_ptr_invoker(memfuncType func,T* t)
        :func_(func),t_(t) {}

    R operator()(Arg... arg) {
        return (t_->*func_)(arg...);
    }
};
/*   用于测试的函数 */
// 测试普通函数
bool some_function(const std::string s) {
  std::cout << s << " This is a common function \n";
  return true;
}
// 测试类成员函数
class some_class {
public:
  bool some_function(const std::string s) {
    std::cout << s << " This is a member function \n";
    return true;
  }
};
// 测试函数对象
class some_function_object {
public:
  bool operator()(const std::string s) {
    std::cout << s << 
      " This is a function object \n";
    return true;
  }
};



int main()
{
    invoker_base<bool, string>* pBase;
    // 调用类成员函数
    some_class s;
    pBase = new member_ptr_invoker<bool, some_class, string>(some_class::some_function, &s);
    pBase->operator()("hello");

    // 调用普通函数
    pBase = new function_ptr_invoker<bool, string>(some_function);
    pBase->operator()("hello");

    // 调用函数对象
    some_function_object func_obj;
    pBase = new function_object_invoker<bool, some_function_object, string>(func_obj);
    pBase->operator()("hello");
    return 0;
}

打印结果:
在这里插入图片描述

2.6 对函数接口进行包装

截止到一步,显然离我们最终的目标还有些差距。虽然到目前为止,我们可以将基类指针指向不同的对象,从而实现对不同类型函数调用,但是我们最终的目的是希望模板能够根据我们传入参数的类型(普通函数、函数对象或者是成员函数)能够进行自动创建相应的对象。于是,我们要需要对接口做一些包装工作。这里主要需要用到模板的重载技术。

template <typename R, typename Arg> class function1 {
  invoker_base<R,Arg>* invoker_;
public:
  function1(R (*func)(Arg)) : 
  invoker_(new function_ptr_invoker<R,Arg>(func)) {}

  template <typename T> function1(R (T::*func)(Arg),T* p) : 
    invoker_(new member_ptr_invoker<R,Arg,T>(func,p)) {}

  template <typename T> function1(T t) : 
    invoker_(new function_object_invoker<R,Arg,T>(t)) {}

  R operator()(Arg arg) {
    return (*invoker_)(arg);
  }

  ~function1() {
    delete invoker_;
  }
};

包装之后测试如下:
注意对比与包装之前的区别。可以看到对接口包装之后,可以根据我们传入的参数类型自动创建相关类型的对象,不再需要我们自己根据类型去创建具体的不同子类对象。

invoker_base<bool, string>* pBase;
    // 调用类成员函数
    some_class s;
    // pBase = new member_ptr_invoker<bool, some_class, string>(some_class::some_function, &s);
    // pBase->operator()("hello");
    function1<bool, string> memfunc(some_class :: some_function, &s);
    memfunc("hello");

    // 调用普通函数
    // pBase = new function_ptr_invoker<bool, string>(some_function);
    // pBase->operator()("hello");
    function1<bool, string> commonfunc(some_function);
    commonfunc("hello");
    // 调用函数对象
    some_function_object func_obj;
    // pBase = new function_object_invoker<bool, some_function_object, string>(func_obj);
    // pBase->operator()("hello");
    function1<bool, string> objfunc(func_obj);
    objfunc("hello");

2.8 对接口做一些调整

不知道有没有注意到,c++11或boost::function中对模板参数的传入类型如下:

// 注意 <>内的形式 
function<bool(string)> f;

但是我们上面实现的function1模板参数的传入类型是下面这样的:

function<bool, string> f;

显示第一种形式更直观,所以我们还得最我们的实现做一些调整。
主要需要用到模板特化技术。

// 定义一个主模板
template <typename R, typename... Arg> 
class function1;
// 然后对模板参数进行特化
template <typename R, typename... Arg> 
class function1<R(Arg...)> {
   // 特化模板中的其它实现完全不变
};

经过上面的调整之后,就可以按照下面的方式使用模板了:

	// 调用类成员函数
    some_class s;
    function1<bool(string)> memfunc(some_class :: some_function, &s);
    memfunc("hello");

    // 调用普通函数
    function1<bool(string)> commonfunc(some_function);
    commonfunc("hello");

    // 调用函数对象
    some_function_object func_obj;
    function1<bool(string)> objfunc(func_obj);
    objfunc("hello");

附 完整代码

#include <iostream>
#include <functional>
using namespace std;

// 实现一个抽象基类,作为调用的接口,然后从这个积累派生出几个不同的子类,从而实现对不同形式的调用
template <typename R, typename... Arg> class invoker_base {
public:
    virtual R operator()(Arg... arg)=0;
};

template <typename R, typename... Arg> class function_ptr_invoker 
  : public invoker_base<R,Arg...> {
    typedef R (*funcType)(Arg...);
    funcType func_;
public:
    
    function_ptr_invoker(funcType func):func_(func) {}

    R operator()(Arg... arg) {
        return (func_)(arg...);
    }
};
// 处理函数对象的版本
template <typename R, typename T, typename... Arg> 
class function_object_invoker : 
  public invoker_base<R,Arg...> {
    T t_;
public:
    function_object_invoker(T t):t_(t) {}

    R operator()(Arg... arg) {
        return t_(arg...);
    }
};

// 实现对类成员函数的调用
template <typename R, typename T, typename... Arg> 
class member_ptr_invoker : 
    public invoker_base<R,Arg...> {
    typedef R (T::*memfuncType)(Arg...);
    memfuncType func_;
    T* t_;
public:
    member_ptr_invoker(memfuncType func,T* t)
        :func_(func),t_(t) {}

    R operator()(Arg... arg) {
        return (t_->*func_)(arg...);
    }
};
/*   用于测试的函数 */
// 测试普通函数
bool some_function(const std::string s) {
  std::cout << s << " This is a common function \n";
  return true;
}
// 测试类成员函数
class some_class {
public:
  bool some_function(const std::string s) {
    std::cout << s << " This is a member function \n";
    return true;
  }
};
// 测试函数对象
class some_function_object {
public:
  bool operator()(const std::string s) {
    std::cout << s << 
      " This is a function object \n";
    return true;
  }
};
template <typename R, typename... Arg> 
class function1;

template <typename R, typename... Arg> 
class function1<R(Arg...)> {
    invoker_base<R,Arg...>* invoker_;
public:
    // 对普通函数进行重载
    function1(R (*func)(Arg...)) : 
    invoker_(new function_ptr_invoker<R,Arg...>(func)) {}
    
    // 对类成员函数进行重载
    template <typename T> 
    function1(R (T::*func)(Arg...),T* p) : 
        invoker_(new member_ptr_invoker<R,T, Arg...>(func,p)) {}
    
    // 对函数对象进行重载
    template <typename T> 
    function1(T t) : 
        invoker_(new function_object_invoker<R,T, Arg...>(t)) {}
    
    // 对接口进行包装
    R operator()(Arg... arg) {
        return (*invoker_)(arg...);
    }

  ~function1() {
    delete invoker_;
  }
};

int main()
{
   
    // 调用类成员函数
    some_class s;
    function1<bool(string)> memfunc(some_class :: some_function, &s);
    memfunc("hello");

    // 调用普通函数
    function1<bool(string)> commonfunc(some_function);
    commonfunc("hello");

    // 调用函数对象
    some_function_object func_obj;
    function1<bool(string)> objfunc(func_obj);
    objfunc("hello");
    return 0;
}

参考资料:
1、boost::function用法详解
2、关于c++11 std::function的模板参数 <_Res(_ArgTypes…)>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值