您的位置:首页 > 其它

template详解

2016-05-07 21:29 141 查看

1. 函数模板

1. 函数模板定义

关键字:“template开头”“参数列表非空”

定义一定要以:template<…>开头(为了解释为什么 inline 在第 2 位置)

定义中模板参数列表不能为空(模板特例化中参数列表可以为空)。

template<tempname T> inline T funcName(const T &a, const T &b) { return (a + b); }  //inline
template<tempname T> T funcName(const T &a, const T &b) { return (a + b); }
template< > void funcName() {  }    //错误:定义时模板参数不能为空。


2. 函数参数

关键字:“非类形形参为常数”“泛型编程规则”“const引用”

在下面的代码中,其中T为类型形参,类型在编译器进行实例化(instantiate)时确定,T还可以用来做类型转换。v为非类型形参,v的实例必须为常数。

template<class T, T v> void foo(T &a, T &b)
{
b = v;
cout<<"a = "<<a<<ends<<"b = "<<b<<endl;
a = b;
}

int main()
{
int m = 1;
int n = 2;
foo<int, m>(m, n);  //error C2971: “foo”: 模板参数“v”:“m”: 局部变量**不能用作非类型参数**
cout<<"a = "<<m<<ends<<"b = "<<n<<endl;
return 0;
}


泛型编程中,函数的参数常常为const引用,来保证参数不仅可为拷贝类型,也可以是非拷贝类型,并且能够保证对源数据的只读性。函数内部的判断符号使用 <,目的是减小函数对要处理类型的要求,因为有的类型肯可能并没有对其他运算符进行重载。

3. 实例化

实例化目前我所了解的有两种:

编译器通过传入的实参进行推断类型形参的类型(即模板实参推断:template argument deduction/*推理*/),但是无法为非类形形参进行推断。

在调用函数时进行指定类型形参非类形形参的类型。

template<class T, T v> void foo(T &a, T &b) { ... }
foo(m, 5);  //error C2783: “void foo(T &,T &)”: 未能为“v”推导 模板 参数

/*正确的实例化*/
template<class T, class V> void foo(T &a, V &b) { ... }
foo(5, 5);  //推断

template<class T, T v> void foo(T &a, T &b) { ... }
foo<int, 6>(5, 5);  //指定


2. 类模板

1. 定义与实例化

大致与函数模板的定义相同。

template<class T> class Bob
{
public:
void func(T &, T &);
template<class It> void foo();
private:
T data;
};


实例化一般在创建对象时指定类型,也可以进行类的特例化。

Bob<int> b; //实例化


2. 类模板的成员函数

关键字:“隐式内联”“部分实例化”“成员模板”

定义在类作用域内的成员函数隐式的被定义为内联函数

成员函数在外部定义时,开头必须以 template<..> 开头。

template<class T> void Bob<T>::func(T &a, T &b)
{
data = a + b;
}


成员模板函数不能是虚函数

在类的外部,只有当遇到类名以后,才算该类的作用域。因此
Bob<T>
以后均为 Bob类的作用域,类的作用域中可以将 template

3. 编译模板

关键字:“定义在头文件”“部分实例化”

当编译器遇到一个模板定义的时候,它并不生成代码。只有当我们实例化出模板一个特定的版本但是时候(即特例化时),编译器才会生成代码。或者在我们使用模板时,编译器才生成代码。

模板函数和模板类的成员函数通常在头文件中定义

编译模板的三个过程:编译模板本身,编译器遇到使用模板,模板实例化。

错误一般在第三个阶段,模板实例化中检测到。模板实例化中是部分实例化,并非全部。仅仅实例化用到的模板。

4. 默认模板参数

默认模板参数时,跟函数默认实参一样,对于一个模板参数,只有当它右侧所有参数都有默认实参时,它才可以具备默认实参。

template<class A = int, class B> A foo2() { ... }   //error C4519: 仅允许在类模板上使用默认模板参数


默认值在使用模板的时候均可以修改(c++11新标准)

template<class A = int, int b = 0> int foo3() { return b; }

int result = foo3<int, 7>();    //result = 7, ok
int result = foo3<double, 7>(); //result = 7, ok


5. 特例化模板(template specialization)

当面对特定的类型,模板不合适的时候,我们可以为这种类型量身打造一款特例化版本。

//定义
template <bool b, typename B, typename C> class {
...
};
//部分特例化
template <> class<true, int, int> {
...
};
//特例化
template <typename B, typename C> class<false, B, C> {
...
};


未了解的关于C++模板的知识

学无止境,还有很多未了解的C++模板知识和C++模板的使用(比如traits..),部分列举如下:

控制实例化:在大系统中,多个文件中实例化相同的模板,开销严重。使用显示实例化(explicit/*明确的*/ instantitation)来避免开销。

extern template class Bob; //声明:告诉编译器,在程序的其他位置(或者其他文件中)有string的实例化定义

tempalte int compare (const int&, const int&); //定义

在运行是绑定删除器,在编译时绑定删除器(与智能指针有关)。

模板的参数推断。

理解std:move

转发:有的时候需要将一个或者多个实参连同类型转发给其他函数。

可变参数的模板

sizeof… 运算符

可变参数模板的编写

包扩展

转发参数包

struct和template连用实现traits

struct里面定义了类型静态常数,需要用结构体名打点调用:

structName::defType i = value;

template<class T, T v>
struct integral_constant {
static const T value = v;
typedef T value_type;
typedef struct integral_constant<T, v> type;
};

int i = struct integral_constant::value;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: