当前位置: 首页 > news >正文

c++11 function模板:模板特化与可变参数函数模板

function是一个类模板,实现了对普通函数、函数对象、lambda表达式、bind表达式、类成员函数等的统一调用。具体用法不不多说,下面举个简答的例子:

#include <iostream>
#include <functional>
using namespace std;
void print(int a,int b,int c) {
    std::cout << "a: " << a << " b: " << b << " c: " << c << "\n";
}
int add(int a, int b) {
	std:: cout << "a + b: " << a + b << std::endl;
}
int main()
{
	// 保存的函数返回值为void,具有3个int型入参
    function<void(int, int, int)> fprint = print;
    fprint(1, 2, 3);
    // 保存的函数返回值为int, 具有两个int型入参
    function<int(int, int) > fadd = add;
    fadd(100, 200);
    return 0;
}

函数的打印结果如下:
a: 1 b: 2 c: 3
a + b: 300

上面函数的用法很简单,但是有两点我特别好奇:
1、模板参数传入方式很特别:
假如我自己定义了一个类模板,用来保存一个具有两个入参的函数指针,函数签名为:
int (int, int),大概会是下面的形式:

// 返回值类型为RT, 两个入参类型分别为T1,T2
template<typename RT, typename T1, typename T2>
class Myfunction {
	// 具体实现
};

那么在定义实例化的时候,大概会是这种形式:

Myfunction<int, int, int> f;

但是注意到,如果使用function来保存,function的形式是下面:

function<int(int,int)> f; // 模板参数为int(int,int), 而不是 int, int, int

2、function可以保存具有不同数量入参的函数, 即可以传入不定参数。
比如在给出的例子中,print有3个参数,add具有两个参数。

为了弄清楚上面的两个问题,我看了一下function的源码以及一些资料,主要用到了两个关键技术:

  • 模板特化
  • 模板不定参数

下面用一个简单的例子来说明,如果能够看懂下面这个例子,相信也就弄明白了上面的两个问题:

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

// 定义一个主模板,该模板不需要具体实现,目的为了实现后面模板的特化
template <typename RT, typename... ArgTypes>
class Function;

// 特化Fucntion模板
template <typename RT, typename... ArgsTypes>
// RT为返回值类型,ArgsTypes是可变模板参数包,ArgsTypes...是参数包扩展,
// 扩展之后的参数与模板传入的参数匹配, 这样就可以传入不定参数
class Function<RT(ArgsTypes...)> {
    private:
    using FuncType = RT(ArgsTypes...);
    FuncType* func_;

    public:
    Function(FuncType func) : func_{func} {}
    void operator() (ArgsTypes... args) {
        func_(args...);
    } 
};
void print(int a,int b,int c) {
    std::cout << "a: " << a << " b: " << b << " c: " << c << "\n";
}
int main()
{
    Function<void(int, int, int)> f = print;
    f(1, 2, 3);
    return 0;
}

相关文章:

  • CSDN竞赛14期题解
  • Qt创建线程的几种方式_创建一个新线程的方法
  • Android自定义ViewGroup布局进阶,完整的九宫格实现
  • 完全开源的代码生成器之code-generator
  • C++:实现量化将期限结构与一组债券相匹配 使用四种不同的拟合方法测试实例
  • 毫米波雷达的那些知识点——增益、阈值、功耗、窗口、RF 发射功率调整、VCO、LNA
  • 1568_AURIX_TC275_电源管理_唤醒配置与状态
  • MySQL表的增删查改(上)
  • 世界杯---人生就是一届又一届世界杯
  • LeetCode 1832. 判断句子是否为全字母句
  • 多数据源解决分布式事务
  • 跳槽一次能涨多少?今天见识到跳槽天花板。
  • 【HTML期末学生大作业】 制作一个简单HTML宠物网页(HTML+CSS)
  • 分享一些冷门但却很实用的css样式
  • 写代码时记录的小技巧
  • 深入了解以太坊
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • CentOS从零开始部署Nodejs项目
  • HTTP 简介
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • Javascript设计模式学习之Observer(观察者)模式
  • Java教程_软件开发基础
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • 订阅Forge Viewer所有的事件
  • 基于遗传算法的优化问题求解
  • 记一次和乔布斯合作最难忘的经历
  • 批量截取pdf文件
  • 前端之React实战:创建跨平台的项目架构
  • 前端知识点整理(待续)
  • 入门到放弃node系列之Hello Word篇
  • 我看到的前端
  • 与 ConTeXt MkIV 官方文档的接驳
  • 中文输入法与React文本输入框的问题与解决方案
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • !! 2.对十份论文和报告中的关于OpenCV和Android NDK开发的总结
  • #HarmonyOS:基础语法
  • (1)STL算法之遍历容器
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (BFS)hdoj2377-Bus Pass
  • (cljs/run-at (JSVM. :browser) 搭建刚好可用的开发环境!)
  • (二)pulsar安装在独立的docker中,python测试
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (附源码)springboot工单管理系统 毕业设计 964158
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (学习日记)2024.01.09
  • (一)VirtualBox安装增强功能
  • (转)母版页和相对路径
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • (转载)虚函数剖析
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .NET Core 版本不支持的问题
  • .NET Micro Framework 4.2 beta 源码探析
  • .NET程序员迈向卓越的必由之路