• 函数指针模板


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

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

    1. //头文件Thread.h
    2. #ifndef __UNI_THREAD_H__
    3. #define __UNI_THREAD_H__
    4. #include
    5. #include
    6. #include
    7. class CThread: public boost::noncopyable
    8. {
    9. public:
    10. typedef boost::function0<void> threadProc;
    11. explicit CThread(const threadProc& proc, std::string threaName);
    12. ~CThread();
    13. void createThread();
    14. bool started()const
    15. {
    16. return mStarted;
    17. }
    18. pid_t tid() const
    19. {
    20. return mTid;
    21. }
    22. const std::string& name()const
    23. {
    24. return mName;
    25. }
    26. int join();
    27. private:
    28. static void* startThread(void* arg);
    29. void runInThread();
    30. private:
    31. bool mStarted;
    32. pthread_t mPthreadId;
    33. pid_t mTid;
    34. threadProc funcProc;
    35. std::string mName;
    36. };
    37. #endif

    主要看 typedef boost::function0 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 模板定义为:

    它其实就是:

    1. template<typename R>
    2. class function0 : public function_base
    3. {
    4. }

     function1 类模板定义为:

    function2 类模板的定义为:

    function10 类模板的定义为:

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

    1. typedef boost::function0<void> threadProc;
    2. //或
    3. typedef boost::function1<void, int> threadProc;
    4. //或
    5. typedef boost::function2<void, int, int> threadProc;
    6. //或
    7. typedef boost::function3<void, int, int, double> threadProc;

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

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

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

    1. CThread::CThread(const threadProc& proc, std::string threaName):
    2. mStarted(false),
    3. mPthreadId(-1),
    4. funcProc(proc),
    5. mName(threaName)
    6. {
    7. }
    8. void CThread::createThread()
    9. {
    10. assert(!mStarted);
    11. mStarted = true;
    12. errno = pthread_create(&mPthreadId, NULL, startThread, this);
    13. if(errno < 0)
    14. {
    15. }
    16. }
    17. void* CThread::startThread(void* arg)
    18. {
    19. CThread *thread = static_cast(arg);
    20. thread->runInThread();
    21. return nullptr;
    22. }
    23. void CThread::runInThread()
    24. {
    25. mTid = CurrentThread::tid();
    26. if(funcProc)
    27. {
    28. funcProc();
    29. }
    30. }

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

    1. result_type operator()( T0 a0 , T1 a1) const
    2. {
    3. if (this->empty())
    4. boost::throw_exception(bad_function_call());
    5. return get_vtable()->invoker
    6. (this->functor , a0 , a1);
    7. }

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

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

    1. //TFuction1
    2. #define FUNCTION_NUMBER 1
    3. #define FUNCTION_CLASS_TYPES typename R, typename T1
    4. #define FUNCTION_TYPES T1
    5. #define FUNCTION_TYPE_ARGS T1 a1
    6. #define FUNCTION_ARGS a1
    7. #define FUNCTION_CLASS_TYPE R, T1
    8. #include "FunctionTemplate.h"
    9. #undef FUNCTION_CLASS_TYPE
    10. #undef FUNCTION_NUMBER
    11. #undef FUNCTION_CLASS_TYPES
    12. #undef FUNCTION_TYPES
    13. #undef FUNCTION_TYPE_ARGS
    14. #undef FUNCTION_ARGS
    15. //TFuction2
    16. #define FUNCTION_NUMBER 2
    17. #define FUNCTION_CLASS_TYPES typename R, typename T1, typename T2
    18. #define FUNCTION_TYPES T1, T2
    19. #define FUNCTION_TYPE_ARGS T1 a1, T2 a2
    20. #define FUNCTION_ARGS a1, a2
    21. #define FUNCTION_CLASS_TYPE R, T1, T2
    22. #include "FunctionTemplate.h"
    23. #undef FUNCTION_CLASS_TYPE
    24. #undef FUNCTION_NUMBER
    25. #undef FUNCTION_CLASS_TYPES
    26. #undef FUNCTION_TYPES
    27. #undef FUNCTION_TYPE_ARGS
    28. #undef FUNCTION_ARGS

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

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

  • 相关阅读:
    《C++PrimePlus》第8章 函数探幽
    【C++初阶】STL详解(一)string类
    C刊级 | Matlab实现GWO-BiTCN-BiGRU-Attention灰狼算法优化双向时间卷积双向门控循环单元融合注意力机制多变量回归预测
    [云原生] K8S 日志收集方案
    RabbitMQ中延迟队列的全方位解析
    Multi-series Time-aware Sequence Partitioning for Disease Progression Modeling
    基于风险的漏洞管理实现高效安全
    大龄程序员三战考研变身考研战神
    9、Java——二维数组案例代码详解
    WEB跨平台桌面程序构建工具对比(Electron、Tauri、Wails)
  • 原文地址:https://blog.csdn.net/tianyexing2008/article/details/126860044