跟我学c++中级篇——模板的基础术语说明

一、类模板术语

1、模板的特化
模板的特化也叫具体化,非常容易理解,就是把模板中的模板参数给定具体的类型。看下面的例子:

//模板
template <typename T,typname N>
class Data
{};
//特化
template<>
class Data<int,int>
{};

特化,特,就是特别的,也就是不同于广泛的,泛型中的特例,这就好明白了。记住,特化前必须有泛型化的定义。

2、全特化

特化分为全特化和偏特化,全特化(full specialization)又称显示特化(explicit specialization)或者显示具体化。指的是把模板类型参数全部给定,像上面的例子就是,这里再举一个简单的:

//模板
template 
class Data
{};
//全特特化
template<>
class Data
{};

注意,全特化可以有多个版本,如上面的可以是int,也可以是short,也可以是等等。

3、偏特化
偏特化(Partial Specialization),也称为局部特化或者部分特化,顾名思义,其实就是只对部分模板参数进行了特化,也即指定类型。这里不举比较容易理解的,举几个不常见的,一般指针也被当成偏特化:

//模板
template 
class Data
{};
//指针偏特化
template 
class Data
{};
///
//模板
template 
class Data
{};
//相同参数偏特化
template
class Data
{};
//单独偏特化
template
class Data
{};

4、实例化和显示实例化
实例化也好理解,就是具体使用模板类或者模板函数,就是实例化。但是这里有一个特别的,叫做显示实例化,Explicit Instantiation,它也叫强制实例化,也叫显示具现化(有的可能也叫全实例化,但这个不太清楚,没找到出处)。来看一下它的代码:

template 
class Stack{};
template class Stack;

和特化的区别在形式上特化有template<>而显示实例化只有template。全特化是指模板参数全部指定,算是活化中的一个特例。而显示实例化是真正的定义出来这个函数,用模板的语义但却如普通类和函数一样使用了。也就是说,实例化的模板,就不再是模板了,和普通的类和函数没有差别。
举一个例子,生产一种配件,正常情况是一种模具(泛型模板),当材料是铜质时,用同一个模板,但里面加了一个标记(特化),而当真正的材料压进模具,出来成品叫实例化。
显示实例化只能一次,而且要在CPP文件中。
4、变量模板
这个在前面刚刚分析过,和constexpr在一起可以在元编程里起到很重要的作用。看下面的代码:

template
constexpr T pi{3.1415926535897932385};

注意,这玩意儿也全特化和偏特化,而且最可有意思的是,它的特化类型并不要求与特化模板匹配。

5、非类型模板参数和模板默认参数
这个也很好理解,那模板的形参不是一个不确定的参数而一个已知的类型,默认参数就更好理解了,将其值定义一个确定的值,如果在实例化模板过程中没有给其定义实参,就使用默认的类型为实参,看代码:

//函数非类型模板参数
template
 T addValue (T x)
 {
 return x + Val;
}
//类非类型模板参数
template
class Buffer
{...};
//默认参数
template>
class Stack {...};
//函数模板默认参数
template
void test (T t, int number = 10);
template 
void test(T t,N n = 0){...}

6、SFINAE和Concepts
Substitution Failure Is Not An Error,替换失败不是错误。用来做模板编译期检查的,常用于模板元编程。可以说如果比较常用到这玩意儿,开发者的水平应该是比较高了。Concepts,概念,可以理解成它的升级版,这个怎么用,在前面反复分析过,这里不再赘述。
7、外部模板
Extern Template,C++11的新功能,主要是减轻编译在大规模编译模板时产生的重复类型实例,降低编译器的工作。它依赖于前面提到的显示实例化,看下面的代码:

//t.h
template 
void test(T) { }
// t1.cpp
#include "t.h"
template void test(int); // 显式实例化
void call()
{
    test(0);
}

// t2.cpp
#include "t.h"
extern template void fun(int); // 外部模板的声明
void invoke()
{
    test(3);
}

8、变参模板
c++11推出的参数不固定的模板,看下面的代码:

template 
class Ex{....};

二、函数模板术语

函数模板与上面术语基本类似,但是函数模板没有偏特化,试想一下,偏特化和重载怎么容易区别呢?但是,在《c++ template》第二版中,却对此提出了一些看法,并且这些想法在c++标准委员会上进行过讨论,只不过没有引起重视罢了。有兴趣可以看看,至于未来会是如何,没人敢说会怎么样。下面看相关的例子:
1、全特化

template 
void test(T) {...}


template<> void test(int); //全特化

2、显示实例化
函数的显示实例化:

template 
void test(T) {...}

//cpp
template void test(int); // 显式实例化

3、变参模板

template 
void test(Args ... args)
{...}

三、模板中的一些具体术语应用

1、this
在普通的类函数中,一般是推荐使用this用来让代码更清晰的表明这是一个类对象的成员。但好多开发者为了简单,就不写了。但是在模板类的继承中,如果子类继承了父类的成员,如果不显示的使用this,会导致编译错误。这时只需要写上this即可。

2、template限定符
这个前面分析过,就是为了让编译器知道使用的是模板类型,帮助编译器进行类型推导的,类似于:

typename Shell::template In::template Deep& p) {
p.template Deep::f(); // inhibit virtual call
}

3、模板的模板参数
也叫双重模板参数,这个在前面也提到过,就是模板的参数,仍然是模板,类似于下面:

template <template <typename T> class  N>
class A{...};
//C++17后
template <template <typename T> typename  N>
class A{...};

注意,新手不要把class单纯当成一个类关键字,所以想当然的使用struct,union这些关键字,使用后者都是错误的。切记。

4、右尖括号的优化
在c++11以前,如果模板实例化中遇到连续的两个>>符号,编译器会把它当成右移符号,从而引起编译错误,所以要在两个右尖括号中间打一个空格,这也是看老的代码时的一个风景,但在c++11之后已经优化正常使用了。例如:

template 
class Data
{typedef T type;};
template 
class D
{};

Data>::type d;//此御的右双尖括号

但是这种方法在处理真的">>"右移时,又会和新编译有冲突,错误和解决方式如下:

template <size_t T>
class D
{};

D<100>>2> xx;//C++11 error
D<(100>>2)> xx;//OK

5、模板的别名
这个也是为了简化模板编程使用的,都知道在模板编程中,可能会有一个很长的类型定义,但typedef又无法在这种情况下作用,所以老的标准中,一般是定义一个模板类,再把此类型定义到这个模板内进行变相的使用,增加了很多的工作量和理解的复杂度。类似于下面:

typedef unsigned int uint32   //ok
//但是要类似偏特化某个类型,比如下面固定KEY为std::string ,value类型可变
typedef  std::map<std::string,std::string> map_string
typedef  std::map<std::string,int> map_string
//C++11 prev
template <typename T>
class map_string{
  typedef std::map<std::string ,T> type;
}
map_string<std::string>::type m1;
//C++11
template <typename T>
using map_string = std::map<std::string,T>;
map_string m1;

6、外部定义成员模板

// member  templates  outside class
template<typename T>
class A
{
public:
   template<typename S>
   void test(const S &s);
};

template<typename T>
template <typename S>
void A<T>::test(const S &s)
{...}

四、总结

这些术语有些是比较为通用的,有的是比较少用的,但在某些书籍中又比较权威,所以了解一些还是有用的。特别是侯捷老师的书里,用法有些不同大家可以对比来印证就知道了什么意思。
这里面其实每个都可以单独拿出来讲很多,本篇主要是综合一下,做一个纲领性的说明。以后如果标准继续更迭,可能会继续在此基础上不断的完善。

你可能感兴趣的:(C++11,c++)