模板优化 运用 function 及 外部模板
我们都知道模板是泛型的,但是,它一旦被实例化就会产生一个实例化的副本。
好了,大家应该能够猜到,低效模板和高效模板的差异了
一般的低效模板:
1.泛型实参表达形式多样导致的低效模板
2.多文件引用同一个模板形成的低效模板
我们接下来就分别来解决上述两种模板的低效问题
泛型实参表达形式多样导致的低效模板
模板头是使得泛型具体化的外交大使(泛型形式参数),但是,会出现这种现象:“相同的实例化类型,但是实参表达形式不同,而导致模板头每次都会为相同的泛型参数实例化一个副本,使得同时存在很多一模一样的实例化模板”。而我们正常情况下,一个实例化类型仅仅对应一个实例化副本即可。
比如说:
template<class T>
void f(const T& t)
{
static int time = ; cout << t << endl;
time++;
cout << "current time = " << time
<< " &time = " << &time << endl;
cout << endl;
} int main()
{
f();
f();
f(3.5);
f();
}
我们模板的实参自动推导为 int int double int ,当然,你也可以显示指定,如:f<int>(2)
f 函数实参为2 3 3.5 8
上述,我们创建的模板实例化副本有两个,分别为 void (*)(const int&)和void (*)(const double&)
我们调用了四次函数f
我们证明一下子
三个int 模板的time值都是延续的,地址都是一样的
而另外的double 模板的time和地址都是新的
但是,这只是很简单的类型,但是面对稍微高级一丢丢的表达式类型,模板则不会进行同类型判定,从而使得模板实例化同一个泛型实参导致多个实例化副本
如:
//test.h
#pragma once #include <iostream>
#include <functional> namespace templatespace
{
using std::cout;
using std::endl;
using std::function;
}; using namespace templatespace; template<class T, class F>
T fun(T v, F f)
{
static int count{ };
count++;
cout << "count = " << count
<< ", &count = " << &count << endl;
return f(v);
} class Fp
{
double z_;
public:
Fp(double z = 1.0) :z_(z) { }
double operator()(double p) { return z_*p; }
}; class Fq
{
double z_;
public:
Fq(double z = 1.0) :z_(z) { }
double operator()(double q) { return z_ + q; }
};
#include "test.h" double couple(double x) { return 2.0*x; }
double square(double x) { return x*x; } int main()
{
double t = 3.5;
cout << "use Function pointer couple:" << endl
<< " " << fun<double>(t, couple) << endl;
cout << "use Function pointer square:" << endl
<< " " << fun<double>(t, square) << endl; cout << "use Function object Fq:" << endl
<< " " << fun<double>(t, Fq()) << endl;
cout << "use Function object Fp:" << endl
<< " " << fun<double>(t, Fp()) << endl; cout << "use Lambda expression 1:" << endl
<< " " << fun<double>(t, [](double u) {return * u; }) << endl;
cout << "use Lambda expression 2:" << endl
<< " " << fun<double>(t, [](double u) {return u*u; }) << endl; }
我们可以很明显地看到,主函数中两两一组,一共有三组
第一组中的第二个函数实参为一个函数指针
第二组中的第二个函数实参为一个函数对象
第三组中的第二个函数实参为一个lambda表达式
安排的明明白白的,这三组的第二个泛型参数实例化后均应为:double (*)(double)
即:它们都接受一个double型参数,然后返回一个double值,我们把这种性质称为特征标。
但是,模板操作起来并不是我们想的:
我们可以看到,只有第一组符合我们的期望,他们的count值是连续的,其量的地址也是相同的,说明这两个模板函数的实例化副本是同一个
那么我们如何让编译器,或者是模板实例化解析的时候将三组的第二个泛型实参接受为同一个类型呢
我们当然是要利用上述提到的特征标来将它们统一起来。
如:std::function<double(int, double)> ttt;
即:ttt对象代表着接受一个int 参数 和 double参数,并返回一个double参数
所以,我们将其运用到模板中 ,很容易的,我们会将代码改动成下面这样:
改动main.cpp
#include "test.h" double couple(double x) { return 2.0*x; }
double square(double x) { return x*x; } using fff = function<double(double)>; int main()
{
double t = 3.5; cout << "use Function pointer couple:" << endl
<< " 函数执行结果为:" << fun(t, fff(couple)) << endl << endl;
cout << "use Function pointer square:" << endl
<< " 函数执行结果为:" << fun(t, fff(square)) << endl << endl;
cout << "use Function object Fq:" << endl
<< " 函数执行结果为:" << fun(t, fff(Fq())) << endl << endl;
cout << "use Function object Fp:" << endl
<< " 函数执行结果为:" << fun(t, fff(Fp())) << endl << endl;
cout << "use Lambda expression 1:" << endl
<< " 函数执行结果为:" << fun(t, fff([](double u) {return * u; })) << endl << endl;
cout << "use Lambda expression 2:" << endl
<< " 函数执行结果为:" << fun(t, fff([](double u) {return u*u; })) << endl << endl;
}
也算是一种类型转换,或者更恰当的说是,抽取特征标。
当然运行结果也如我们所料
上述验证了,三组测试的第二个泛型参数的特征标是一样的,即他们的类型相同。、
当然,上述改动,有点花时间,我们可以在模板上面做改动,而无需主函数调用时每次修改:
template<class T>
T fun(T v, function<T(T)> f)
{
static int count{ };
count++;
cout << "count = " << count
<< ", &count = " << &count << endl;
return f(v);
}
而且,还省去了第二个泛型参数的自动推导
所以,经过上面的一系列动作,我们把三组测试数据,由原来的5份模板实例,优化到了一份模板实例。
多文件引用同一个模板形成的低效模板
但是我做了大量测试,仍没有看到上述所说的多份模板实例化副本的现象发生。
#pragma once
#include <iostream>
using std::cout;
using std::endl; template<class T>
void opera(const T& x)
{
static int count{ };
count++;
cout << "count = " << count
<< ", &count = " << &count << endl;
cout << "value : " << x << endl << endl;
} void test1();
test.h
#include "test.h" void test1()
{
opera(3.14);
}
test.cpp
#pragma once class test2
{
public:
test2(){}
void solve(double);
};
test2.h
#include "test2.h"
#include "test.h" void test2::solve(double x)
{
opera(x);
}
test2.cpp
#include "test.h"
#include "test2.h" void fun(double x)
{
opera(x);
} int main()
{
double r{ 3.14 };
test2 _2;
test1();
fun(r);
_2.solve(r);
}
main.cpp
上述描述中提到,创建两个cpp然后引用模板头文件,我创建了三个cpp,分别引用模板头文件,然后进行同类型泛型参数测试,结果:所有的模板实例化副本只有一个:
如有高见,请于下方留言,谢谢
模板优化 运用 function 及 外部模板的更多相关文章
- 模板函数(template function)出现编译链接错误(link error)之解析
总的结论: 将template function 或者 template class的完整定义直接放在.h文件中,然后加到要使用这些template function的.cpp文件中. 1. 现 ...
- javascript模板库jsrender加载并缓存外部模板文件
前一篇说了jsrender嵌套循环的使用,在SPA的应用中,广泛使用的一个点就是view模板,使用了SPA之后,每个业务页面不再是独立的html,仅仅是一个segment,所以通常这些segment会 ...
- groot 引入外部模板
index7.html <html><head> <title>groots引入外部模板van</title> <script src=" ...
- C++11外部模板
[C++11之外部模板] 在标准C++中,只要在编译单元内遇到被完整定义的模板,编译器都必须将其实例化(instantiate).这会大大增加编译时间,特别是模板在许多编译单元内使用相同的参数实例化. ...
- C++11 : 外部模板(Extern Template)
在C++98/03语言标准中,对于源代码中出现的每一处模板实例化,编译器都需要去做实例化的工作:而在链接时,链接器还需要移除重复的实例化代码.显然,让编译器每次都去进行重复的实例化工作显然是不必要的, ...
- vue组件化之模板优化及注册组件语法糖
vue组件化之模板优化及注册组件语法糖 vue组件化 模板 优化 在 https://www.cnblogs.com/singledogpro/p/12054895.html 这里我们对vue.js ...
- JavaScript模板引擎artTemplate.js——如何引入模板引擎?
artTeamplate.js在github上的地址:artTemplate性能卓越的js模板引擎 引入模板引擎,就是引入外部javascript啦,并且artTemplate.js不依赖其他第三方库 ...
- Win10系列:JavaScript 项目模板中的文件和项模板文件
通过上面内容的学习,相信读者已经对各种项目模板和项模板有了大致的了解,本节将进一步介绍项目模板中默认包含的项目文件以及项模板文件,首先讲解这些文件中的初始内容以及作用,然后介绍在一个页面中如何添加控件 ...
- 根据模板导出Excel报表并复制模板生成多个Sheet页
因为最近用报表导出比较多,所有就提成了一个工具类,本工具类使用的场景为 根据提供的模板来导出Excel报表 并且可根据提供的模板Sheet页进行复制 从而实现多个Sheet页的需求, 使用本工具类时 ...
随机推荐
- 一个JavaScript组件都需要哪些基础api
{ init: function() { // 模块初始化,包括属性初始化和配置初始化及调用父类的初始化方法 } ,build: function() { // 模块构建,包括子模块构建,dom构建, ...
- 【leetcode 简单】 第七十题 有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词. 示例 1: 输入: s = "anagram", t = "nagaram" ...
- CMD命令利用tasklist与taskkill关闭程序
昨天远程服务器后,服务器无故卡住了,鼠标各种延迟与无反应,想在进程管理器里关闭程序也卡住,想点击重启系统也卡死无反应.纠结后win+R打开了cmd用shutdown重启才算搞定.重启期间思考了下,如何 ...
- RobotFramework安装扩展库包Selenium2Library(三)
Robot Framework扩展库包 http://robotframework.org/#libraries 一,自动化测试web端 1,pip安装SeleniumLibrary pip inst ...
- 阿里云slb+https 实践操作练习
如果只是练习按照文档步骤逐步执行即可. 如果是业务需要,只供参考. 有道笔记链接->
- 六、springcloud之配置中心Config
一.配置中心提供的核心功能 Spring Cloud Config为服务端和客户端提供了分布式系统的外部化配置支持.配置服务器为各应用的所有环境提供了一个中心化的外部配置.它实现了对服务端和客户端对S ...
- show engine innodb status 详细介绍
Contents Header1 SEMAPHORES. 1 LATEST DETECTED DEADLOCK. 3 TRANSACTIONS. 5 什么是purge操作... 5 FILE I/O. ...
- ASP.NET中Literal,只增加纯粹的内容,不附加产生html代码
页面代码 <div style="float: right; color: #666; line-height: 30px; margin-right: 12px;" id= ...
- Oracle约束
1.非空约束 DROP TABLE member PURGE; CREATE TABLE member( mid NUMBER, name ) NOT NULL ); 2.唯一约束 DROP TABL ...
- OA项目Spring.Net代替抽象工厂(三)
Servrvice层的代码: <?xml version="1.0" encoding="utf-8" ?> <objects xmlns=& ...