函数指针模板

        我们知道要使用一个函数指针,则必须声明一个函数指针类型,然后再定义一个函数指针变量。我们一般声明的函数指针,如:void (*funcPro)(int),那用这个函数指针类型定义的变量,可以指向一个“返回值是 void,带一个 int 类型的参数的函数”。假如要使用其他类型的返回值的,或是不同的参数类型的,那只能再去声明一个函数指针。今天看一种模板,它可以指定返回值和参数类型(及参数个数),然后就可以很轻松的定义出所需要的函数指针了。

        首先看一个如何使用 boost (为什么使用 boost? 好像c++11里很多特性都是从boost代码移植的)里的类模板:

//头文件Thread.h

#ifndef __UNI_THREAD_H__
#define __UNI_THREAD_H__

#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <pthread.h>


class CThread: public boost::noncopyable
{
public:
    typedef boost::function0<void> threadProc;
    explicit CThread(const threadProc& proc, std::string threaName);
    ~CThread();

    void createThread();

    bool started()const 
    {
        return mStarted;
    }

    pid_t tid() const
    {
        return mTid;
    }

    const std::string& name()const
    {
        return mName;
    }

    int join();
private:
    static void* startThread(void* arg);

    void runInThread();
private:
    bool       mStarted;
    pthread_t  mPthreadId;
    pid_t      mTid;
    threadProc funcProc;
    std::string     mName;
};

#endif

主要看 typedef boost::function0<void> threadProc; 这里的 function0 其实是一个类模板,它的实参是 void。那这个类模板是怎么定义的呢?我们跳到它的定义处是这样的:

我们看到它的类名是  BOOST_FUNCTION_FUNCTION,然而这个名称和 function0 有什么联系呢?这个其实是一个宏定义:

而 BOOST_JOIN 也是一个宏:

这些宏最终的目的是把 两个参数连在一起,即经过 BOOST_JOIN(function,BOOST_FUNCTION_NUM_ARGS) 后,BOOST_FUNCTION_FUNCTION=functionBOOST_FUNCTION_NUM_ARGS,而这个 BOOST_FUNCTION_NUM_ARGS 是一个宏,那这个宏是什么呢?

这是在 /usr/include/boost 目录下搜索出来的结果(我CentOS已经下载安装了 boost库,所以有这个目录),所以这个 BOOST_FUNCTION_NUM_ARGS 有可能是这些值,那也就是说BOOST_FUNCTION_FUNCTION=function0(或function1、function2、function3、function4、function5、function6、function7、function8、function9、function10)。那是不是有这些 functionX 模板定义呢?通过对上面的头文件 Thread.h 进行预编译:

g++ -std=c++11 -I./include -E ./include/Thread.h -o macroFunction

得到的文件 macroFunction 可以看到类模板的基本声明:

 然后真正的 function0 模板定义为:

它其实就是:

template<typename R>
class function0 : public function_base
{
    
}

 function1 类模板定义为:

function2 类模板的定义为:

function10 类模板的定义为:

所以经过预编译,已经生成了 11 个类模板的声明及定义。这样你就可以这样使用:

typedef boost::function0<void> threadProc;

//或
typedef boost::function1<void, int> threadProc;

//或
typedef boost::function2<void, int, int> threadProc;

//或
typedef boost::function3<void, int, int, double> threadProc;

 在使用的时候,模板名称中为0,1,2,3,... 10 表示除第一个外实参的个数,第一个表示返回值。如最开始代码中的使用:

class CThread: public boost::noncopyable
{
public:
    typedef boost::function0<void> threadProc;
    explicit CThread(const threadProc& proc, std::string threaName);

构造函数CThread 的第一个参数就是一个类模板,使用:

CThread::CThread(const threadProc& proc, std::string threaName):
mStarted(false),
mPthreadId(-1),
funcProc(proc),
mName(threaName)
{

}

void CThread::createThread()
{
    assert(!mStarted);
    mStarted = true;

    errno = pthread_create(&mPthreadId, NULL, startThread, this);
    if(errno < 0)
    {

    }
}

void* CThread::startThread(void* arg)
{
    CThread *thread = static_cast<CThread*>(arg);
    thread->runInThread();
    return nullptr;
}

void CThread::runInThread()
{
    mTid = CurrentThread::tid();
    if(funcProc)
    {
        funcProc();
    }
}

 创建线程后,执行线程函数,线程函数里调用了 funcProc();  这里 funcProc 是一个类模板定义出来的类,像这种 funcProc() 来执行的方法,在c++里被称为仿函数,即变量是一个类,但可以像函数一样调用。那这个怎么实现的呢?其实就是重载了() ,这样在执行 funcProc() 时,就是调用类的重载 operator(),查看之前预编译的文件中有:

result_type operator()( T0 a0 , T1 a1) const
{
  if (this->empty())
	boost::throw_exception(bad_function_call());

  return get_vtable()->invoker
		   (this->functor , a0 , a1);
}

这个是 function2 类模板里的 operator() 重载。所以,经过上面这些介绍,我们可以知道,在经过预编译后,已经有了 function0~function10 的类模板了,只有在使用的时候才会生成对应的代码,即我这样使用:typedef boost::function2<void, int, int> threadProc; 那编译出来的.o 文件里肯定有这个 function2 的声明及定义,用 nm 命令可以查看:

这个boost库里的function代码看起来还是复杂的,而以前的老代码(c++11没出来前)也用到类似的模板,只是比这个简单,可读性也比较好。如下列的声明:

//TFuction1
#define FUNCTION_NUMBER 1
#define FUNCTION_CLASS_TYPES typename R, typename T1
#define FUNCTION_TYPES T1
#define FUNCTION_TYPE_ARGS T1 a1
#define FUNCTION_ARGS a1
#define FUNCTION_CLASS_TYPE R, T1
#include "FunctionTemplate.h"
#undef FUNCTION_CLASS_TYPE
#undef  FUNCTION_NUMBER
#undef  FUNCTION_CLASS_TYPES
#undef	FUNCTION_TYPES
#undef	FUNCTION_TYPE_ARGS
#undef	FUNCTION_ARGS

//TFuction2
#define FUNCTION_NUMBER 2
#define FUNCTION_CLASS_TYPES typename R, typename T1, typename T2
#define FUNCTION_TYPES T1, T2
#define FUNCTION_TYPE_ARGS T1 a1, T2 a2
#define FUNCTION_ARGS a1, a2
#define FUNCTION_CLASS_TYPE R, T1, T2
#include "FunctionTemplate.h"
#undef FUNCTION_CLASS_TYPE
#undef  FUNCTION_NUMBER
#undef  FUNCTION_CLASS_TYPES
#undef	FUNCTION_TYPES
#undef	FUNCTION_TYPE_ARGS
#undef	FUNCTION_ARGS

这个 FUNCTION_NUMBER 和 上面boost 代码里的 BOOST_FUNCTION_NUM_ARGS 是一样的,其类模板定义为:

 也是一样,经过预编译,会生成 TFunction1、TFunctino2的定义,这样就可以使用了,讲到这里应该了解了这个 boost::functionX<> 的用法,其实现细节还需要仔细读代码,也可以参考这里:Member Function Pointers and the Fastest Possible C++ Delegates - CodeProject

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值