【十八】类模板(下)

本篇接着上一篇的内容介绍!

1、类模板多个类型参数

和函数模板一样,一个类模板也可以定义多个类型参数!
如下:

#include <iostream>
using namespace std;

template <typename T1, typename T2>
class Test
{
public:
  void test(T1 a, T2 b)
  {
    cout << static_cast<T1>(a + b) << endl;
  }
};

int main()
{
  Test<double, int> ti;   //必须使用具体类型定义对象

  ti.test(3.14159, 10);

  return 0;
}

 
 
2、类模板的局部特化

类模板可以被局部特化

  • 可以指定类模板的特定实现,并要求某些类型参数仍然必须得由使用模板的用户指定

示例:

#include <iostream>
using namespace std;

template <typename T1, typename T2>
class Test    //该模板类要求两个不同的类型参数
{
public:
  void test(T1 a, T2 b)
  {
    cout << "void test(T1 a, T2 b)" << endl;
    cout << static_cast<T1>(a + b) << endl;
  }
};

//特化1
template <typename T>
class Test<T, T>    //该模板类要求两个相同的类型参数
{
public:
  void test(T a, T b)
  {
    cout << "void test(T a, T b)" << endl;
    cout << a + b << endl;
  }
};

//特化2
template <typename T>
class Test<T, int>    //该模板类要求一个类型参数和一个int型参数
{
public:
  void test(T a, int b)
  {
    cout << "void test(T a,  int b)" << endl;
    cout << a + b << endl;
  }
};

//特化3
template <typename T1, typename T2>
class Test<T1*, T2*>    //该模板类要求两个不同的指针类型参数
{
public:
  void test(T1* a, T2* b)
  {
    cout << "void test(T1* a, T2* b)" << endl;
    cout << static_cast<T1>(*a + *b) << endl;
  }
};



int main()
{
  int i = 10;
  double d = 3.14159;

  Test<int, double> ti;
  ti.test(i, d);

  Test<double, int> td;
  td.test(d, i);

  Test<double*,int*> tdp;
  tdp.test(&d,&i);
  return 0;
}

思考:
  为什么需要特化,而不重新定义新类?

  • 特化和重新定义新类看上去没有本质区别,但是如果定义新类,那么将变成一个类模板和一个新类,使用的时候需要考虑究竟是用类模板还是用新类
  • 而特化可以统一的方式使用类模板和特化类,编译器自动优先选择特化类

 
 
3、类模板和函数模板的非类型模板参数–数值参数

函数模板和类模板的模板参数可以是普通数值

示例:

#include <iostream>

using namespace std;

//类模板
template <typename T, int N>
class Test
{
private:
  int value;
public:
  Test()
  {
    value = N;
  }
  void print()
  {
    cout << "value = " << value << endl;
  }
};

//函数模板
template <typename T, int N>    //在这里声明了类型参数和数值参数,可在函数中直接使用
void func()
{
  T array[N] = {0};
  for(int i = 0; i < N; i++)
  {
    array[i] = i + 1;
    cout << array[i] << endl;
  }
}

int main()
{
  Test<int,10>  ti;     //类模板使用方式
  ti.print();

  func<double,5>();     //模板函数调用方式

  return 0;
}

扩展练习:

假如让我们计算从1到N的和,要求计算快速且性能开销最小,该如何计算?

答:
方法一:写一个函数,用循环。。。。
方法二:写一个函数,用等差数列求和公式。。。
方法三:。。。。。

以上提到的方法其实都不是很好,因为到头来我们得到的结果还是要经过函数调用,并且在运行时才能完成计算!有一个好方法可以在编译期让编译器帮我们做这个计算!

示例:

利用非类型模板参数和特化,无开销计算1到N的和!

#include <iostream>

using namespace std;

//类模板
template <int N>
class Sum
{
public:
  static const int VALUE = Sum<N-1>::VALUE + N;
  //我们利用递归的思想来求和:前N项的和 = 前N-1项的和 + N;依次类推!
};

//特化
template <>
class Sum<1>
{
public:
  static const int VALUE = 1;
  //这里让static作用于变量会让该变量在全局数据区分配空间
  //然后,const作用于变量,意味着要定义一个常量,
  //最后,给这个变量赋予了值为1的字面值常量,所以该变量会被放入符号表!
};


int main()
{
  //整个计算过程在编译期间就完成了!
  Sum<100> s;
  cout << s.VALUE << endl;

  return 0;
}

非类型模板参数的限制

  • 变量不能作为非类型模板参数
  • 浮点数类对象不能作为非类型模板参数,浮点数这个原因好像是由于历史原因造成的,现代C++编译器不成问题!
  • 全局指针不能作为非类型模板参数
  • 综上所诉,非类型模板参数最好就只使用整型数据

Tip:

  编译器的推导过程是在编译阶段完成的。因此,编译器的推导必须依赖于特化类,否则推导过程无法结束。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值