C/C++编程:模板的基本语法 您所在的位置:网站首页 有关模板的规范文件 C/C++编程:模板的基本语法

C/C++编程:模板的基本语法

2024-07-16 08:24| 来源: 网络整理| 查看: 265

Template Class基本语法 基本语法

声明:

template < typename T> class ClassA;

定义:

template < typename T> class ClassA { T member; }

template表示接下来将会定义一个模板。和函数一样,模板也有一系列参数。这些参数都被囊括在template之后的< >中。在上文的例子中,typename T便是模板参数。 来看一个函数声明:

void ff(int a);

typename T可以类比int a, T是形参,typename表示模板参数中的T将匹配一个类型。

我们可以用类似ClassA来实例化类ClassA,那么ClassA等同于:

// 注意:这并不是有效的C++语法,只是为了说明模板的作用 typedef class { int member; } ClassA; 怎么使用

定义一个类模板:

template class vector { public: void push_back(T const&); void clear(); private: T* elements; };

对于C++来说,类型最重要的作用之一就是用它去产生一个变量,因此,可以这样用:

vector intArray; vector floatArray;

此时我们就可以执行以下的操作,获得我们想要的结果:

intArray.push_back(5); floatArray.push_back(3.0f);

变量定义的过程可以分成两步来看:第一步,vector将int绑定到模板类vector上,获得了一个“普通的类vector”;第二步通过“vector”定义了一个变量。

我们把通过类型绑定将模板类变成“普通的类”的过程,称之为模板实例化(Template Instantiate)。实例化的语法是:

模板名

当然,在实例化过程中,被绑定到模板参数上的类型(即模板实参)需要与模板形参正确匹配。 就如同函数一样,如果没有提供足够并匹配的参数,模板便不能正确的实例化。

模板类的成员函数

C++11正式废弃模板导出这一特性,因此在模板类的变量在调用成员函数的时候,需要看到完整的成员函数定义。因此现在的模板类中的成员函数,通常是以内联的方式实现的。

template class vector { public: void clear() { // Function body } private: T* elements; };

当然,我们也可以将vector::clear的定义部分放在类型之外,只不过这个时候的语法就显得蹩脚许多:

template class vector { public: void clear(); // 注意这里只有声明 private: T* elements; }; template void vector::clear() // 函数的实现放在这里 { // Function body }

在成员函数实现的时候,必须要提供模板参数。此外,为什么类型名不是vector而是vector呢? 如果你了解过模板的偏特化与特化的语法,应该能看出,这里的vector在语法上类似于特化/偏特化。实际上,这里的函数定义也确实是成员函数的偏特化

综上,正确的成员函数实现如下所示:

template // 模板参数 void vector /*看起来像偏特化*/ ::clear() // 函数的实现放在这里 { // Function body } Template Function基本语法 template void foo(T const& v); template T foo(); template U foo(T const&); template void foo() { T var; // ... }

使用:

#include #include template T Add(T a, T b) { return a + b; } int main() { int a = 5; int b = 3; int result = Add(a, b); } 整型也可以是Template参数

模板参数除了类型外(包括基本类型、结构、类类型等),也可以是一个整型数(Integral Number)。这里的整型数比较宽泛,包括布尔型,不同位数、有无符号的整型,甚至包括指针。我们将整型的模板参数和类型作为模板参数来做一个对比:

template class TemplateWithType; template class TemplateWithValue;

我想这个时候你也更能理解 typename 的意思了:它相当于是模板参数的“类型”,告诉你 T 是一个 typename。

按照C++ Template最初的想法,模板不就是为了提供一个类型安全,容器调试的宏吗?有类型就够了,为什么要引入整形参数呢?考虑宏,它除了代码替换,还有一个作用是作为常量出现。所以整形模板参数最基本的用途就是定义一个常数。比如:

template struct Array { T data[Size]; }; Array arr;

相当于

class IntArrayWithSize16 { int data[16]; // int 替换了 T, 16 替换了 Size }; IntArrayWithSize16 arr;

另外,因为模板的匹配是在编译时完成的,所以实例化模板的时候所使用的参数,也必须要在编译期就能确定:

template class A {}; void foo() { int x = 3; A a; // 正确! A b; // error C2971: '_1_3::A' : template parameter 'i' : 'x' : a local variable cannot be used as a non-type argument }

因为x不是一个编译期常量,所以 A 就会告诉你,x是一个局部变量,不能作为一个模板参数出现。

嗯,这里我们再来写几个相对复杂的例子:

template class A { public: void foo(int) { } }; template class B {}; template class C {}; template class D {}; template int Add(int a) // 当然也能用于函数模板 { return a + i; } void foo() { A a; B b; // 模板参数可以是一个无符号八位整数,可以是模板生成的类;可以是一个指针。 C c; // 模板参数可以是一个bool类型的常量,甚至可以是一个函数指针。 D d; // 丧心病狂啊!它还能是一个成员函数指针! int x = Add(5); // x == 8。因为整型模板参数无法从函数参数获得,所以只能是手工指定啦。 } template class E {}; // ERROR: 别闹!早说过只能是整数类型的啦!


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有