C++模板编程-模板基础重点
模板基础
1、模板参数自动推导,如果是已知的参数类型与个数,这调用模板时可以不写类型。
Cout<<max<int>(1,3);可以写为Cout<<max(1,3);这样看起来与普通函数没有区别。
2、最新标准C++11允许使用参数模板默认值,指定默认值后,如下
template < typename T0 = float,
typename T1,
typename T2 = float,
typename T3,
typename T4>
T2 func(T1 v1,T3 v3,T4 v4); template < typename T0,
typename T1,
typename T2,
typename T3,
typename T4>
T2 func(T1 v1,T3 v3,T4 v4)
{
T0 static sv0 = T0();
T2 static sv2 = T2(); cout<<"\t v1: "<< v1
<<"\t v2: "<< v3
<<"\t v4: "<< v4
<<"\t || sv0: "<< sv0; T2 v2 = sv2; sv0 -= ;
sv2 -= ;
return v2;
}
3、函数模板中的静态局部变量
静态局部变量只有在调用同一个函数时才会操作静态变量,如果参数个数或者类型不同,则不会调用同一个模板函数实例,那局部静态变量也不会改变。
4、函数模板的声明和定义应该放在一个头文件里,这样引用时就不会出现各种问题。但是这样会出现重复引用问题。
5、针对上面出现的重复问题,C++解决方法是:在链接时识别及合并等价的模板实例。这里还要用到命名空间,对于自己写的库,一定要包括到自己的命名空间里,这样就不怕重复问题了。
6、类亦模板,与函数模板相同,但不支持模板实参推导机制,类模板如下
template <typename T = int>//此处可以指定默认值
struct list_node
{
T value;
list_node *next;
};
类模板使用起来和函数模板类似
list_node<int>int_node;
list_node<float>float_node;
如果指定默认值的话,也可以省去类型,但是“<>”不能省略。
list_node<>int_node;
7、C++规定: 在一个类模板内部出现的自身模板名,等价于该模板被调用时所生成的实例。
8、类模板同样可以用于派生生成子模板。
常用的类模板用法:
1 成员函数模板,2 友元函数模板,3 类模板的静态成员
类模板的静态成员,如果有两个文件都生成了含有静态成员变量的类模板的实例,那么在编译时会分配两个静态变量的内存地址,但是在链接时编译器会随机选择一个静态变量的内存地址作为最终的存储空间,从而使不同目标文件中的多个等价模板实例共享一套静态承运存储空间。
9、模板参数类型(typename or class指定的值)
整数模板参数,函数指针模板参数,指针及引用模板参数(局部变量指针或者引用不能用于模板参数),成员函数指针模板参数,模板型模板参数(模板的参数是另一个类模板)。
//成员函数指针模板参数 #include <iostream>
using namespace std; class some_value;
typedef int (some_value::* some_value_mfp )(int);//some_value_mfp是指向一类函数的指针 template <some_value_mfp func>//func 是一个成员函数指针型模板参数
int call(some_value & value,int op)
{
return (value.*func)(op);//“.*”操作符和“->*”操作符会在这个情况下使用
} class some_value
{
int value;
public:
some_value(int _value) {value = _value;}
int add_by(int op) {return value += op;}
int sub_by(int op) { return value -= op;}
int mul_by(int op) {return value *= op;}
}; int main()
{
some_value v0();
cout<<call<&some_value::add_by>(v0,)<<endl;
cout<<call<&some_value::sub_by>(v0,)<<endl;
cout<<call<&some_value::mul_by>(v0,)<<endl;
getchar();
return ;
}
成员函数指针模板参数
//模板型模板参数 #include <iostream>
using namespace std; //func是一个模板型模板函数,包装foreach要对没一个元素进的操作
template<template<typename TT> class Func,typename T>//只有类模板才能做为模板参数
void foreach(T array[],unsigned size)
{
Func<T> func;
for (unsigned i = ; i < size ; i ++)
{
func(array[i]);
}
}
//三种操作都封装成函数类模板,可以通过括号操作符进行调用
template <typename T>
struct inc
{
void operator ()(T &v)const
{
++v;
}
};
template <typename T>
struct decs
{
void operator ()(T &v)const
{
--v;
}
};
template <typename T>
struct print
{
void operator ()(T &v)const
{
cout<<' '<<v;
}
}; int main()
{
int array[] = {,,,,,,,};
foreach<print>(array,);
cout<<endl; foreach<inc>(array,);
foreach<print>(array,);
cout<<endl; foreach<decs>(array,);
foreach<print>(array,);
getchar();
return ;
}
模板型模板参数
10、模板特例
模板的一种特殊情况。如果按集合划分的话,那就模板特例就是模板的一个真子集。
例如vector<bool> 模板特例,因为sizeof(bool) 返回一个字节,所以在申请空间时得到的就是一个字节(8bit)来保存一个bool型变量(1bit),有点浪费,所以有必要对其进行压缩处理,这是模板特例的一种方式。
//正常模板声明
template <typename T>
class my_vector
{
public:
//constructor use malloc to apply memory
my_vector(unsigned _size):array((T *)malloc(sizeof(T)*_size)),size(),block_size(_size) {}
~my_vector(){if(array) free(array);} void push_back(T const &elem) throw (runtime_error)
{
if(size == block_size)
{
//已有空间已经用完,需要申请更大空间
block_size *= ;
T * new_array = (T*)realloc(array,block_size* sizeof(T));
if(new_array != NULL)
array = new_array;
else //申请增加空间失败,内存耗尽
{
free(array);
array = NULL;
throw runtime_error("out of memory");
}
}
array[size++] = elem;
}
T operator[](unsigned i) {return array[i];}
const T &operator[](unsigned i) const {return array[i];}
//get how much memory we used
unsigned get_mem_size() const {return block_size * sizeof(T);}
protected:
private:
T *array;
unsigned size;
unsigned block_size; }; //模板特例声明,必须在正常模板声明之后
template<>
class my_vector<bool>
{
private:
int *array;
unsigned size;
unsigned block_size; //一个段(segment)即一个整数值,段大小即为一个整数所能容纳的最多布尔值数 = sizeof(int)*8
const static unsigned seg_size; public:
my_vector(unsigned _size):array((int*)malloc(_size*sizeof(int))),size(),block_size(_size){}
~my_vector() { if(array) free(array);} void push_back(bool elem) throw (runtime_error)
{
if (size == block_size*seg_size)
{
block_size *= ;
int *new_array = (int*)realloc(array,block_size*sizeof(int));
if (new_array != NULL)
array = new_array;
else
{
free(array);
array = NULL;
throw runtime_error("out of memory");
}
}
set(size++,elem);
} void set(unsigned i , bool elem)
{
if (elem)
{
array[i/seg_size] |= (0x01 << (i % seg_size));
}
else
{
array[i/seg_size] &= ~(0x01 <<(i%seg_size));
}
} bool operator[] (unsigned i) const
{
return (array[i/seg_size] &(0x01 << (i%seg_size))) != ;
} unsigned get_mem_size() const {return block_size*sizeof(int);}
}; const unsigned my_vector<bool>::seg_size = sizeof(int) * ; int main()
{
my_vector<char> vi();
my_vector<bool> vb();
for (unsigned i = ; i < ; i ++)
{
vi.push_back('a'+ i);
vb.push_back((i%) == );
} cout<<"char "<<vi.get_mem_size()<<endl;
cout<<"bool "<<vb.get_mem_size()<<endl; for (unsigned i = ; i < ; i ++)
{
cout<<' '<<vi[i];
}
cout<<endl; for (unsigned i = ; i < ; i ++)
{
cout<<' '<<vb[i];
}
cout<<endl; getchar();
return -;
}
模板特例 my_vector
结果:
总结:针对某一问题,我们可以首先为绝大多数情况设计模板。然后针对集中特殊情况设计模板特例,从而尽量用最小的代码量得到尽量最优化的解决方法。
11、C++规定:同一个模板可以有多个特例。
使用时匹配原则是:匹配最特殊的那个。
比较两个特例A和B,如果所有能匹配A的模板参数值都能匹配B,而反之不成立的话,那就确定A比B特殊。即A是B的真子集。
#include <iostream>
using namespace std; template <typename T0,typename T1, typename T2>
struct S
{
string id() { return "General";}
};
//第三个参数必须为char
template <typename T0,typename T1>
struct S<T0,T1,char>
{
string id() {return "Specialization #1";}
};
//第二第三个参数必须为char
template <typename T0>
struct S<T0,char,char>
{
string id(){return "Specialization #2";}
};
//第一个参数为int,且第二第三个参数相同
template <typename T>
struct S<int,T,T>
{
string id() {return "Specialization #3";}
};
12、函数模板的特例与重载
C++只允许为函数模板声明完全特例,而禁止声明部分特例。需要用到部分特例的情况可以用函数模板重载来实现。
//函数模板特例与重载 #include <iostream>
using namespace std; template <typename T>
void print(T v)
{
cout<<v<<endl;
} //定义成模板特例(完全特例)
template <>
void print<char>(char v)
{
cout<<'\''<<v<<'\''<<endl;
} //模板特例,模板参数依赖推导(完全特例)
template<>// const char *v有函数实参可以推导出模板实参的类型,故可以省略template<>
void print(const char *v)
{
cout<<'"'<<v<<'"'<<endl;
} //函数重载
inline void print(string const &v)
{
cout<<"\'\'\'"<<v<<"\'\'\'"<<endl;
} inline void print(bool v)
{
cout<<(v?"true":"false")<<endl;
} //函数模板重载
template <typename T>
void print(T *v)
{
cout<<'*';
print(*v);
}
函数模板特例与重载
13、分辨重载
普通函数重载和函数模板重载后调用就会有多个匹配函数,这是就要做选择。
C++准则:
1、 两个候选函数中如果一方其形参列表类型与调用实参列表各类型更匹配,则淘汰另一方。
2、 两函数如果其形参列表类型同等匹配实参列表类型,若一方为函数模板实例而另一方为非模板函数,则取非模板函数而淘汰函数模板实例。
3、 两函数如果其形参列表类型同等匹配实参列表类型时,若两者均为函数模板实例,则取更加特殊的一方而淘汰另一方。
14、编译期的条件判断逻辑
模板特例实际上提供了一种判断逻辑—当模板参数满足某一匹配条件时所匹配特例实现,否则用通例实现。不过这种判断是在编译器实现的。所输入的值必须事先知道并且确定。
例子是:不使用循环及条件判断语句打印1~100之间的数字。
//编译期的条件判断逻辑
#include <iostream>
using namespace std; //通用模板实例
template <int i >
void print()
{
print<i->();
cout<<i <<endl;
} //模板特例
template <>
void print<>()
{
cout<<<<endl;
} int main()
{
print<>(); getchar();
return ;
}
编译期的条件判断逻辑
C++模板编程-模板基础重点的更多相关文章
- AJAX编程模板
AJAX一直以来没怎么接触,主要是做JSON数据在服务器和客户端之间传递的时候,被玩坏了,对它莫名的不可爱,最近心理阴影小了,于是又来看看它....... AJAX即“Asynchronous Jav ...
- c++模板 与 泛型编程基础
C++模板 泛型编程就是以独立于任何特定类型的方式编写代码,而模板是泛型编程的基础. (1)定义函数模板(function template) 函数模板是一个独立于类型的函数,可以产生函数的特定类型版 ...
- C++之模板编程
当我们越来越多的使用C++的特性, 将越来越多的问题和事物抽象成对象时, 我们不难发现:很多对象都具有共性. 比如 数值可以增加.减少:字符串也可以增加减少. 它们的动作是相似的, 只是对象的类型不同 ...
- AutoCAD二次开发(2020版)--4,使用ARX向导创建编程模板(框架)--
手动创建ObjectARX应用程序非常麻烦,在此步骤中,将介绍ObjectARX向导. 在这里,我们将使用ObjectARX向导创建我们的ObjectARX应用程序. 本节的程序的需求是,接收CAD用 ...
- c++模板编程-typename与class关键字的区别
最近一直在研究c++模板编程,虽然有些困难,但希望能够坚持下去.今天,在书上看见一个讨论模板编程typename与class两个关键字的区别,觉得挺有意义的,就把它们给总结一下. 先看一个例子: te ...
- C#编程の模板
C#泛型编程已经深入人心了.为什么又提出C#模板编程呢?因为C#泛型存在一些局限性,突破这些局限性,需要使用C#方式的模板编程.由于C#语法.编译器.IDE限制,C#模板编程没有C++模板编程使用方便 ...
- 06 Zabbix4.0系统CISCO交换机告警模板规划信息(基础)
点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 06 Zabbix4.0系统CISCO交换机告警模板规划信息(基础) 1. Host groups ...
- C++编程模板2
C++编程模板2 #include <iostream> using namespace std; /* */ int main(){ int ans; printf("%d\n ...
- C++ 11可变参数接口设计在模板编程中应用的一点点总结
概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量 ...
随机推荐
- 《译》准备做一些 AR/增强现实的 翻译
中文这方面资料实在少之又少. 准备做一些这方面翻译,关注于Vuforia, Unity3d, Hololens等方面. 如有问题.建议,随时联系.Fell free ton contact me.
- 线程池模块thernd
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import time def task(i): print ...
- LAMP stack-5.6.22 (OpenLogic CentOS 7.2)
平台: CentOS 类型: 虚拟机镜像 软件包: apache2.4.20 mysql5.6.30 php5.6.22 apache application server basic softwar ...
- Asp.net MVC 服务端验证多语言错误
服务端验证用户提交信息时为了实现多语言使用了资源文件,如: using System.ComponentModel.DataAnnotations; public class UserModel { ...
- 打造颠覆你想象中的高性能,轻量级的webform框架-----如何替换webform的垃圾控件(第一天)
前文描述: 随着.net 推出 MVC框架以来,webform 与 mvc 的争论一直没有停止过,一直以来 mvc 的 拥护者远远高于 webform,但是webfrom的有些优势又是mvc而无法替 ...
- CSS之常见文字样式整理
常见文字样式 行高:line-height,当我i们将行高的大小设置成当前元素的高度时,可以实现当行文本在当前元素中垂直方向居中显示的效果 水平对齐方式:text-align:left|center| ...
- object-detection-crowdai数据处理
import os file=os.listdir('/home/xingyuzhou/object-detection-crowdai') file.sort(key= lambda x:int(x ...
- 3_HA介绍和安装部署
一.hadoop 2.x产生背景 1.hadoop 1.x中hdfs和mr在高可用和扩展性等方面存在问题.2.hdfs存在的问题:NN单点故障,难以应用于在线场景:NN压力过大,内存受限,影响系统扩展 ...
- JQuery模拟点击页面上的所有a标签,触发onclick事件
注意: 这种方法需要给所有的a标签加上id属性 页面加载完成模拟点击所有的a标签: <script> $(function () { // 模拟点击页面上的所有a标签,触发onclick事 ...
- SummerVocation_Learning--java的String 类
java中String属于java.lang的package包,是一个类.代表不可变的字符序列. String类的常见构造方法: String(String original),创建一个对象为orig ...