【C++】你想要的——印刷模板儿(上)

简介: 【C++】你想要的——印刷模板儿

一、泛型编程

泛型编程是什么意思呢?我们通过下面的例子来具体了解:

void Swap(int& left, int& right)
{
  int temp = left;
  left = right;
  right = temp;
}
void Swap(double& left, double& right)
{
  double temp = left;
  left = right;
  right = temp;
}
int main()
{
  int a = 1, b = 2;
  Swap(a, b); 
    double c=1.33,d=2.33;
    Swap(a,b)
}

就拿交换函数来说,当我们交换不同类型的变量的值,那就需要不停的写交换函数的重载,这样代码复用率就较低,那我们能不能创造一个模板呢??


一个Swap的模板,但是我可以用不同的类型去实现这个模板,继而试用它。


如果在 C++ 中,也能够存在这样一个 模具 ,通过给这个模具中 填充不同材料 ( 类型 ) ,来 获得不同材料的铸件 ( 即生成具体类型的代码)。

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

二、模板(初阶)

模板分为:函数模板和类模板


1.函数模板

1.单参数类型

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定 类型版本。

就拿Swap来说:  typename 是 用来定义模板参数 关键字,T是类型(也可以用class,(class T))

template<typename T>
void Swap(T& left, T& right)
{
  T temp = left;
  left = right;
  right = temp;
}
int main()
{
      int a = 1, b = 2;
      Swap(a, b);
        int x = 1, y = 2;
    Swap(x, y);
    double m = 1.1, n = 2.2;
    Swap(m, n);
    char p = 'a', q = 'b';
    Swap(p, q);
        Swap(m,a);//不同类型
}

那么,具体是怎样实现的呢?

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。

编译器通过类型推演,将函数模板进行实例化,对应的T就会替换成具体的类型,模板实例化是用几个实例化几个,不是所有不同类型都提前模板实例化。


1.当变量类型相同,但是变量不同,调用Swap();模板实例化只会实例化一个,因为虽然变量不同,但类型相同,模板实例化就是将T换成具体的类型。


2.当Swap(m,a),变量是不同类型时,会发生什么??


因为在推演void Swap(T& left, T& right);时,T的类型不明确,就会发生错误(推演报错),直接报错


但如果不用模板,我们自己这样:

void Swap(int& left, int& right)
{
  int temp = left;
  left = right;
  right = temp;
}
int main()
{
  int a=2;
  double b=2.22;
  Swap(a,b);
}

可能有人就会想:在Swap(a,b)中,会不会a和b发生饮食类型转化呢?较小的类型转化成较大的类型。


当然不会:隐式类型转化只有在 赋值:b=3;(产生临时变量);函数传参的时候(产生临时变量),才会发生隐式类型转化。


函数形参是引用,当类型是引用时,我们就要小心:是否会发生权限放大?当b传值时,中间的临时变量具有常性(只读),而形参是可读可写,权限就会放大,也是不可以通过的,除非加了const,但是加了const就无法交换了,所以这样还是行不通的!


自动推演实例化和显式实例化:

template<class T>
T Add(const T& left, const T& right)
{
  return left + right;
}
int main()
{
  int a1 = 10, a2 = 20;
  double d1 = 10.1, d2 = 20.2;
  // 自动推演实例化
  cout << Add(a1, a2) << endl;
  cout << Add(d1, d2) << endl;
  cout << Add((double)a1, d2) << endl; //强制类型转化也是产生临时变量,不是改变a1
  cout << Add(a1, (int)d2) << endl;
  // 显示实例化
  cout << Add<double>(a1, d2) << endl;//隐式类型转化
  cout << Add<int>(a1, d2) << endl;
  return 0;
}

在自动推演实例化中,必须强转,不然还是和之前问题一样,该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int 或者 double类型而报错。 (推演报错)


不强转情况:显示实例化,:在函数名后的<>中指定模板参数的实际类型(我让你怎么来你就怎么来!)


在函数名后加入了指定模板参数后,就会在实例化时,T直接是指定的类型,这样就会发生隐式类型转换。


注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅

Add(a1, d1);

此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化

2.多参数类型

template

template<class t1,class t2>
t1 Add(const t1& left, const t2& right)
{
  return left + right;
}
int main()
{
  int a = 1, b = 2;
  double m = 2.22, n = 3.33;
  cout << Add(a, b) << endl;
  cout << Add(m, n) << endl;
  cout << Add(a, m) << endl;
  cout << Add(n, b) << endl;
}

此时,当Add(不同类型时),就不会发生推演错误,你是什么类型就会推演成什么模板函数


目录
相关文章
|
2月前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
116 10
|
28天前
|
安全 编译器 C++
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
43 4
|
28天前
|
算法 编译器 C++
【C++】模板详细讲解(含反向迭代器)
C++模板是泛型编程的核心,允许编写与类型无关的代码,提高代码复用性和灵活性。模板分为函数模板和类模板,支持隐式和显式实例化,以及特化(全特化和偏特化)。C++标准库广泛使用模板,如容器、迭代器、算法和函数对象等,以支持高效、灵活的编程。反向迭代器通过对正向迭代器的封装,实现了逆序遍历的功能。
34 3
|
1月前
|
编译器 C++
【c++】模板详解(1)
本文介绍了C++中的模板概念,包括函数模板和类模板,强调了模板作为泛型编程基础的重要性。函数模板允许创建类型无关的函数,类模板则能根据不同的类型生成不同的类。文章通过具体示例详细解释了模板的定义、实例化及匹配原则,帮助读者理解模板机制,为学习STL打下基础。
31 0
|
2月前
|
编译器 程序员 C++
【C++打怪之路Lv7】-- 模板初阶
【C++打怪之路Lv7】-- 模板初阶
18 1
|
2月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
61 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
2月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
91 2
|
2月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
45 2
|
2月前
|
存储 算法 编译器
【C++】初识C++模板与STL
【C++】初识C++模板与STL
|
2月前
|
编译器 C++
【C++】模板进阶:深入解析模板特化
【C++】模板进阶:深入解析模板特化
104 0