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

查看楼盘卖房信息在哪查/百度seo优化排名

查看楼盘卖房信息在哪查,百度seo优化排名,wordpress 利用工具,大连手机自适应网站建设公司一、改变模板的“游戏规则”C 没有办法限制类型参数的范围,我们可以使用任意一种类型来实例化模板。但是模板中的语句(函数体或者类体)不一定就能适应所有的类型,可能会有个别的类型没有意义,或者会导致语法错误。比如…

784090e3f0ef6a6a502de622eff51a05.png

一、改变模板的“游戏规则”

C++ 没有办法限制类型参数的范围,我们可以使用任意一种类型来实例化模板。但是模板中的语句(函数体或者类体)不一定就能适应所有的类型,可能会有个别的类型没有意义,或者会导致语法错误。

比如说在模板函数内比较值的大小,这对一些基本数据类型有用,但是却不能用来比较结构体、类和数组等数据——我们并没有针对它们进行重载。对于指针来说,比较的是地址大小,而不是指针指向的数据,所以也没有现实意义。总之,我们必须对它们进行单独处理。

模板是一种泛型技术,它能接受的类型是宽泛的、没有限制的,并且对这些类型使用的算法都是一样的(函数体或类体一样)。但是现在我们希望改变这种“游戏规则”,让模板能够针对某种具体的类型使用不同的算法(函数体或类体不同),这在 C++ 中是可以做到的,这种技术称为模板的显式具体化(Explicit Specialization)。

模板函数如何显式实例化?看一下这个例子:

#include <iostream>
#include <string>
using namespace std;
typedef struct{string name;float score;
} STU;template<typename T> const T & Max(const T &a, const T &b){return a > b ? a : b;
}template<> const STU & Max<STU>(const STU &a, const STU &b){return a.score > b.score ? a : b;
}ostream & operator << (ostream & out, const STU &stu){out << stu.name << ' ' << stu.score;return out;
}int main(int argc, char const *argv[]){int a = 10, b = 20;cout<<Max(a, b)<<endl;STU stu1 = {"Sam", 90}, stu2 = {"Amy", 100};cout<<Max(stu1, stu2);return 0;
}

请格外注意这一行:

template<> const STU & Max<STU>(const STU &a, const STU &b)

Max<STU>中的STU表明了要将类型参数 T 具体化为 STU 类型,原来使用 T 的位置都应该使用 STU 替换,包括返回值类型、形参类型、局部变量的类型。Max 只有一个类型参数 T,并且已经被具体化为 STU 了,这样整个模板就不再有类型参数了,类型参数列表也就为空了,所以模板头应该写作template<>。另外,Max<STU>中的STU是可选的,因为函数的形参已经表明,这是 STU 类型的一个具体化,编译器能够逆推出 T 的具体类型。简写方式如下所示:

template<> const STU& Max(const STU& a, const STU& b);

在 C++ 中,对于给定的函数名,可以有非模板函数、模板函数、显示具体化模板函数以及它们的重载版本,在调用函数时,显示具体化优先于常规模板,而非模板函数优先于显示具体化和常规模板。

那么,类模板如何显式具体化呢?请看下面这个例子:

#include <iostream>
using namespace std;template<class T1, class T2> class Point{
public:Point(T1 x, T2 y): m_x(x), m_y(y){ }
public:T1 getX() const{ return m_x; }void setX(T1 x){ m_x = x; }T2 getY() const{ return m_y; }void setY(T2 y){ m_y = y; }void display() const;
private:T1 m_x;T2 m_y;
};template<class T1, class T2>  
void Point<T1, T2>::display() const{cout<<"x="<<m_x<<", y="<<m_y<<endl;
}template<> class Point<char*, char*>{
public:Point(char *x, char *y): m_x(x), m_y(y){ }
public:char *getX() const{ return m_x; }void setX(char *x){ m_x = x; }char *getY() const{ return m_y; }void setY(char *y){ m_y = y; }void display() const;
private:char *m_x; char *m_y;  
};void Point<char*, char*>::display() const{cout<<"x="<<m_x<<" | y="<<m_y<<endl;
}int main(){( new Point<int, int>(10, 20) ) -> display();( new Point<int, char*>(10, "E180") ) -> display();( new Point<char*, char*>("E180", "N210") ) -> display();return 0;
}

以上方法也称模板类的全特化,一个类被称为全特化类的条件:1.必须有一个主模板类 2.模板类型被全部明确化。也许你会问,既然有非类型参数,那么在显示具体化里面有没有类似的、只为一部分参数提供实参的方法?当然有,模板类型中,可以有被明确化的部分和没有被明确化的部分,这称为偏特化(编译器的设计者怎么会不考虑到如此灵活的设计呢)。可以把上面这个例子改一改:

#include <iostream>
using namespace std;template<class T1, class T2> class Point{
public:Point(T1 x, T2 y): m_x(x), m_y(y){ }
public:T1 getX() const{ return m_x; }void setX(T1 x){ m_x = x; }T2 getY() const{ return m_y; }void setY(T2 y){ m_y = y; }void display() const;
private:T1 m_x;T2 m_y;
};template<class T1, class T2>  
void Point<T1, T2>::display() const{cout<<"x="<<m_x<<", y="<<m_y<<endl;
}template<typename T2>
class Point<char*, T2>{
public:Point(char *x, T2 y): m_x(x), m_y(y){ }
public:char *getX() const{ return m_x; }void setX(char *x){ m_x = x; }T2 getY() const{ return m_y; }void setY(T2 y){ m_y = y; }void display() const;
private:char *m_x; T2 m_y; 
};template<typename T2> 
void Point<char*, T2>::display() const{cout<<"x="<<m_x<<" | y="<<m_y<<endl;
}int main(){( new Point<int, int>(10, 20) ) -> display();( new Point<int, char*>(10, "E180") ) -> display();( new Point<char*, char*>("E180", "N210") ) -> display();return 0;
}

对主版本模板类、全特化类、偏特化类的调用优先级从高到低进行排序是:全特化类>偏特化类>主版本模板类。这样的优先级顺序对性能也是最好的。切记一定实现主模板,不然编译器认不出特化的是哪个参数、有没有写全。

写到这里我才发现,前一节写的非具体参数原来就是模板函数的偏特化,考虑不周不好意思TAT。。。,包括偏特化全特化这些特有名词也是半路才发现的。。。

二、模板的实例化与具体实例化

模板(Templet)并不是真正的函数或类,它仅仅是编译器用来生成函数或类的一张“图纸”。模板不会占用内存,最终生成的函数或者类才会占用内存。由模板生成函数或类的过程叫做模板的实例化(Instantiate),相应地,针对某个类型生成的特定版本的函数或类叫做模板的一个实例(Instantiation)。

模板的实例化是按需进行的,用到哪个类型就生成针对哪个类型的函数或类,不会提前生成过多的代码。也就是说,编译器会根据传递给类型参数的实参(也可以是编译器自己推演出来的实参)来生成一个特定版本的函数或类,并且相同的类型只生成一次。实例化的过程也很简单,就是将所有的类型参数用实参代替。

另外需要注意的是类模板的实例化,通过类模板创建对象时并不会实例化所有的成员函数,只有等到真正调用它们时才会被实例化;如果一个成员函数永远不会被调用,那它就永远不会被实例化。这说明类的实例化是延迟的、局部的,编译器并不着急生成所有的代码。

通过类模板创建对象时,一般只需要实例化成员变量和构造函数。成员变量被实例化后就能够知道对象的大小了(占用的字节数),构造函数被实例化后就能够知道如何初始化了;对象的创建过程就是分配一块大小已知的内存,并对这块内存进行初始化。

额外说一下,模板的工作是帮助编译器生成参数数据类型不同的代码,从这个角度理解模板可以是编译器的一组指令,帮我们生成目标代码吧hhh

通常模板的实例化是在调用函数或者创建对象时由编译器自动完成的,不需要程序员引导,因此称为隐式实例化。相对应的,我们也可以通过代码明确地告诉编译器需要针对哪个类型进行实例化,这称为显式实例化。

编译器在实例化的过程中需要知道模板的所有细节:对于函数模板,也就是函数定义;对于类模板,需要同时知道类声明和类定义。我们必须将显式实例化的代码放在包含了模板定义的源文件中,而不是仅仅包含了模板声明的头文件中。这样一来,就可以把模板的声明和定义放在不同文件里面了。

举个例子,来看看函数模板的显示实例化吧:

#define MAXNAME 128
struct job
{
char name[MAXNAME]:
int salary;
};template<class T>
void swap(T &a, T &b )
{T temp;temp = a;a = b;b = temp;
};template void swap<int>(int &a, int & b);  
template<> void swap<job>(job &a, job &b)   
{int salary:salary = a.salary:a.salary = b.salary;b.salary = salary;
};

再写一个例子,看一下类的显式实例化:

#include <iostream>
using namespace std;const int MAXSIZE = 1000;
template<class T>
class Seqlist
{
public:Seqlist() { length = 0; }Seqlist(const T a[], int n);int locate(T x);T get(int i);
private:T data[MAXSIZE];int length;
};
template<class T>
Seqlist<T>::Seqlist(const T a[], int n)
{if (n > MAXSIZE)throw"数组长度超过最大长度";for (int i = 0; i < n; i++){data[i] = a[i];}length = n;
}
template<class T>
T Seqlist<T>::get(int i)
{if (i<1 || i>length)throw"位置非法";return data[i - 1];
}
template<class T>
int Seqlist<T>::locate(const T x)
{for (int i = 0; i < length; i++)if (x == data[i])return i + 1;return 0;
}
int main()
{int a[7] = { 1,2,3,4,5,6,7 };Seqlist<int>list(a, 7);int v = list.locate(5);cout << v << endl;int d = list.get(5);cout << d << endl;
}

特别说明一下,具体化和实例化的区别:

具体化:即显式具体化,与实例化不同的是,它也是一个模板定义,但它是对特定类型的模板定义。显式具体化使用下面两个等价的声明之一:

实例化:在程序中的函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板为特定类型生成函数定义时,得到的是模板实例。这即是函数模板的实例化。

有人会说,那具体化不就是实例化基础上多此一举吗?不是的,有时要针对特定数据类型做不同的处理,所以需要具体化。

在程序运行时匹配模板时,遵循的优先级是:具体化模板优先于常规模板,而非模板函数优先于具体化和常规模板。

在笔者看来,程序运行时完成了实例化的工作,而具体化是由程序员完成的。

三、显式实例化的缺陷

C++ 支持显式实例化的目的是为「模块化编程」提供一种解决方案,这种方案虽然有效,但是也有明显的缺陷:程序员必须要在模板的定义文件(实现文件)中对所有使用到的类型进行实例化。这就意味着,每次更改了模板使用文件(调用函数模板的文件,或者通过类模板创建对象的文件),也要相应地更改模板定义文件,以增加对新类型的实例化,或者删除无用类型的实例化。

一个模板可能会在多个文件中使用到,要保持这些文件的同步更新是非常困难的。而对于库的开发者来说,他不能提前假设用户会使用哪些类型,所以根本就无法使用显式实例化,只能将模板的声明和定义(实现)全部放到头文件中;C++ 标准库几乎都是用模板来实现的,这些模板的代码也都位于头文件中。

总起来说,如果我们开发的模板只有我们自己使用,那也可以勉强使用显式实例化;如果希望让其他人使用(例如库、组件等),那只能将模板的声明和定义都放到头文件中了。[1]

(如有转载请注明作者与出处,欢迎建议和讨论,thanks)

参考

  1. ^http://c.biancheng.net/view/vip_2326.html
http://www.jmfq.cn/news/5175811.html

相关文章:

  • 网站轮播图居中代码怎么写/网络营销的应用
  • 佛山外包网站建设/苏州新闻今天最新消息新闻事件
  • 做海报的网站什么编辑器/免费com网站域名注册
  • 重庆做网站哪家公司好/关键词优化公司电话
  • 济宁网站建设/百度搜索引擎优化详解
  • 企业文化建设网站建设/最新域名查询
  • 做网站的主要任务/百度推广网站一年多少钱
  • c# asp.net网站开发书/海外网站
  • 神州顺利办深一做网站/百度网盟
  • 做网站一般都选哪家/网站怎么seo关键词排名优化推广
  • 帮别人建网站赚钱吗/新手seo要学多久
  • 好用的网站/国内销售平台有哪些
  • 网站建设的基本流程图/广告平台网站有哪些
  • 织梦图片网站源码下载/培训机构怎么找
  • 江苏手机网站建设/网络优化这个行业怎么样
  • wordpress点击文章跳转外站/优化课程设置
  • 罗湖住房和建设局网站官网/近三天重大新闻摘抄
  • 有框架有模板怎么做网站/百度品牌
  • 佛山做外贸网站特色/适合网络营销的产品
  • 网站建设专业的公司排名/营销渠道模式有哪些
  • wordpress首页代码压缩/百度关键词优化查询
  • 网站销售策划/网络营销具有哪些特点
  • wordpress下一篇调用/百度推广优化怎么做
  • 有没有可以做游戏的网站吗/深圳市seo点击排名软件价格
  • 最火的做牛排沙拉网站/宁波seo搜索引擎优化
  • 做网站大家都找谁/百度网站提交收录入口
  • 博罗做网站哪家强/微信广告推广价格表
  • 交友网站建设的栏目规划/百度云搜索入口
  • 网站开发常遇到客户问题/百度推广如何代理加盟
  • 爱做网站yeele/快速优化系统