泛型编程中,模板会根据传入类型的不同,生成多种实例,相对低效。

模板编程:

#include <iostream>

using namespace std;

//未使用函数包装器
template <typename T,typename F>
T use_f(T v, F f)
{
static int count = ;
count++;
cout<<"use_f count = "<<count<<": &count"<<&count<<endl;
return f(v);
} class Fp
{
private:
double z_;
public:
Fp(double z = 1.0):z_(z){}
double operator ()(double p) {return z_*p;}
}; class Fq
{
private:
double z_;
public:
Fq(double z = 1.0):z_(z){}
double operator ()(double p) {return z_+p;}
}; double dub(double x){return 2.0*x;}
double square(double x){return x*x;} int main(int argc, char *argv[])
{
double y = 1.2;
cout<<"Function pointer dub:"<<endl;
cout<<" --"<<use_f(y,dub);
cout<<"Function pointer square:"<<endl;
cout<<" --"<<use_f(y,square);
cout<<"Function pointer Fp:"<<endl;
cout<<" --"<<use_f(y,Fp());
cout<<"Function pointer Fq:"<<endl;
cout<<" --"<<use_f(y,Fq());
cout<<"Function pointer lambada1:"<<endl;
cout<<" --"<<use_f(y,[](double u){return u*u;});
cout<<"Function pointer lambada2:"<<endl;
cout<<" --"<<use_f(y,[](double u){return u+2.5;});
return ;
}

模板编程的优势是高度抽象,将算法统一封装,但是其根据类型实例化的特性也造成了其低效性。

以上执行结果,通过查看静态模板函数中,静态数据的地址,其产生了5个函数实例。代码量受传入类型的影响产生了巨大的增量。

通过std::function来减少模板的实例化:

#include <iostream>
#include <functional>
using namespace std; //使用函数包装器
template <typename T,typename F>
T use_f(T v, F f)
{
static int count = ;
count++;
cout<<"use_f count = "<<count<<": &count"<<&count<<endl;
return f(v);
} class Fp
{
private:
double z_;
public:
Fp(double z = 1.0):z_(z){}
double operator ()(double p) {return z_*p;}
}; class Fq
{
private:
double z_;
public:
Fq(double z = 1.0):z_(z){}
double operator ()(double p) {return z_+p;}
}; double dub(double x){return 2.0*x;}
double square(double x){return x*x;} int main(int argc, char *argv[])
{
double y = 1.2;
// cout<<"Function pointer dub:"<<endl;
// cout<<" --"<<use_f(y,dub);
// cout<<"Function pointer square:"<<endl;
// cout<<" --"<<use_f(y,square);
// cout<<"Function pointer Fp:"<<endl;
// cout<<" --"<<use_f(y,Fp());
// cout<<"Function pointer Fq:"<<endl;
// cout<<" --"<<use_f(y,Fq());
// cout<<"Function pointer lambada1:"<<endl;
// cout<<" --"<<use_f(y,[](double u){return u*u;});
// cout<<"Function pointer lambada2:"<<endl;
// cout<<" --"<<use_f(y,[](double u){return u+2.5;}); std::function<double(double)> fdub = dub;
std::function<double(double)> fsquare = square;
std::function<double(double)> fFp = Fp();
std::function<double(double)> fFq = Fq();
std::function<double(double)> lambada1 = [](double u){return u*u;};
std::function<double(double)> lambada2 = [](double u){return u+2.5;}; cout<<"Function pointer dub:"<<endl;
cout<<" --"<<use_f(y,fdub);
cout<<"Function pointer square:"<<endl;
cout<<" --"<<use_f(y,fsquare);
cout<<"Function pointer Fp:"<<endl;
cout<<" --"<<use_f(y,fFp);
cout<<"Function pointer Fq:"<<endl;
cout<<" --"<<use_f(y,fFq);
cout<<"Function pointer lambada1:"<<endl;
cout<<" --"<<use_f(y,lambada1);
cout<<"Function pointer lambada2:"<<endl;
cout<<" --"<<use_f(y,lambada2); return ;
}

所有的静态变量只有一个地址,也就是说模板 函数只产生了一个实例,其类型只需要匹配是一个std::function<double(double)>传入的对象即可,模板的效率大为提高。

但是看来好像代码量并未减少甚至还有些许增多,下面我们通过优化来解决这个问题。

熊掌与鱼:

#include <iostream>
#include <functional>
using namespace std; //模板中使用函数包装器
template <typename T>
T use_f(T v, std::function<T(T)> f)
{
static int count = ;
count++;
cout<<"use_f count = "<<count<<": &count"<<&count<<endl;
return f(v);
} class Fp
{
private:
double z_;
public:
Fp(double z = 1.0):z_(z){}
double operator ()(double p) {return z_*p;}
}; class Fq
{
private:
double z_;
public:
Fq(double z = 1.0):z_(z){}
double operator ()(double p) {return z_+p;}
}; double dub(double x){return 2.0*x;}
double square(double x){return x*x;} int main(int argc, char *argv[])
{
double y = 1.2;
//这里需要<double>使得std::function<T(T)>实例化为具体的对象
cout<<"Function pointer dub:"<<endl;
cout<<" --"<<use_f<double>(y,&dub);
cout<<"Function pointer square:"<<endl;
cout<<" --"<<use_f<double>(y,square);
cout<<"Function pointer Fp:"<<endl;
cout<<" --"<<use_f<double>(y,Fp());
cout<<"Function pointer Fq:"<<endl;
cout<<" --"<<use_f<double>(y,Fq());
cout<<"Function pointer lambada1:"<<endl;
cout<<" --"<<use_f<double>(y,[](double u){return u*u;});
cout<<"Function pointer lambada2:"<<endl;
cout<<" --"<<use_f<double>(y,[](double u){return u+2.5;}); return ;
}

实例化与代码量都减少了,鱼和熊掌兼得。

使用std::function改善模板的低效性的更多相关文章

  1. 用lambda表达式和std::function类模板改进泛型抽象工厂设计

  2. 剖析std::function接口与实现

    目录 前言 一.std::function的原理与接口 1.1 std::function是函数包装器 1.2 C++注重运行时效率 1.3 用函数指针实现多态 1.4 std::function的接 ...

  3. C++11中的std::function

    看看这段代码 先来看看下面这两行代码: std::function<void(EventKeyboard::KeyCode, Event*)> onKeyPressed; std::fun ...

  4. 【转】C++11中的std::function

    原文地址:http://www.jellythink.com/archives/771 看看这段代码 先来看看下面这两行代码: std::function<void(EventKeyboard: ...

  5. 第12课 std::bind和std::function(3)_std::function可调用对象包装器

    1. std::function (1)首先是一个类模板,用于包装可调用对象.可以容纳除了类成员(函数)指针之外的所有可调用对象. (2)可以将普通函数,lambda表达式和函数对象类统一起来.尽管它 ...

  6. 第10课 std::bind和std::function(1)_可调用对象

    1. 几种可调用对象(Callable Objects) (1)普通函数指针或类成员的函数指针 (2)具有operator()成员函数的类对象(仿函数).如c++11中的std::function类模 ...

  7. std::function介绍 -转载

    类模版std::function是一种通用.多态的函数封装.std::function的实例可以对任何可以调用的目标实体进行存储.复制.和调用操作,这些目标实体包括普通函数.Lambda表达式.函数指 ...

  8. callable object与新增的function相关 C++11中万能的可调用类型声明std::function<...>

    在c++11中,一个callable object(可调用对象)可以是函数指针.lambda表达式.重载()的某类对象.bind包裹的某对象等等,有时需要统一管理一些这几类对象,新增的function ...

  9. C++11 std::function用法

    转自 http://www.hankcs.com/program/cpp/c11-std-function-usage.html function可以将普通函数,lambda表达式和函数对象类统一起来 ...

随机推荐

  1. Python之并行编程笔记

    概述: 非并发: 1 程序由单个步骤序列构成  2 包含独立子任务的程序执行性能低 并发:  1 异步.高效  2 分解子任务.简化流程与逻辑 进程process:1 一个程序的执行实例  2 每个进 ...

  2. 二、点亮LED

    接着上一章,本章来实现控制LED的亮灭操作: 一.驱动框架 #include <linux/fs.h> #include <linux/init.h> /* 定义文件内私有结构 ...

  3. shell习题第23题:检测网卡流量

    [题目要求] 写一个脚本,检测网卡流量并记录到日志,需要按照如下格式并一分钟统计一次(只需统计外网网卡,网卡名称eth0) 2019-06-07 1:11 eth0 input: 1000bps et ...

  4. oracle 、mysql 取昨天 前天 本周 数据

    查询今天数据: SELECT COUNT(1) FROM T_CALL_RECORDS WHERE TO_CHAR(T_RKSJ,'YYYY-MM-DD')=TO_CHAR(SYSDATE,'YYYY ...

  5. 关于MySQL的驱动org.gjt.mm.mysql.Driver

    今天看了一个比较老视频使用org.gjt.mm.mysql.Driver来驱动连接,便试了一下看看怎么样,结果一直连不上数据库,后来看了tomcat的后台发现有报这个问题,于是把驱动改成com.mys ...

  6. tint2

    #---------------------------------------------# TINT2 CONFIG FILE#---------------------------------- ...

  7. opencv-02--图像的邻域操作

    图像的邻域操作 很多时候,我们对图像处理时,要考虑它的邻域,比如3*3是我们常用的,这在图像滤波.去噪中最为常见,下面我们介绍如果在一次图像遍历过程中进行邻域的运算. 下面我们进行一个简单的滤波操作, ...

  8. 【原创】大叔经验分享(94)jdbc连接mysql、sqlserver、oracle

    Mysql driver下载:https://mvnrepository.com/artifact/mysql/mysql-connector-java import java.sql.*; publ ...

  9. java封装数据类型——Long

    Long 是长整型 long 的封装数据类型.我们知道 long 相对于 int 的差异就是数据表示的范围扩大了,其它大部分特性都是一样的.所以 Long 跟 Integer 大部分方法都是相同的. ...

  10. Django入门第一步:构建一个简单的Django项目

    Django入门第一步:构建一个简单的Django项目 1.简介 Django是一个功能完备的Python Web框架,可用于构建复杂的Web应用程序.在本文中,将通过示例跳入并学习Django.您将 ...