【C++】模板

简介: 一下搞懂C++模板,学会函数模板和类模板

目录

前言

1.函数模板

1.1使用

1.2实现逻辑

1.3实例化

1.4匹配规则

2.类模板

2.1使用

实例化


前言

🎗️照以前的想法,若我们想实现一个交换函数,需要这样写。

void swap(int& x, int& y)
{
  int tmp = x;
  x = y;
  y = tmp;
}
int main()
{
  int a = 5, b = 6;
  swap(a, b);
  return 0;
}

image.gif

🎗️若想写通用的交换函数呢?根本没完没了,换一个类型就要重新写一次就算有了函数重载也不能减少多少工作量

void swap(int& x, int& y)
{
  int tmp = x;
  x = y;
  y = tmp;
}
void swap(char& x, char& y)
{
  int tmp = x;
  x = y;
  y = tmp;
}
void swap(double& x, double& y)
{
  int tmp = x;
  x = y;
  y = tmp;
}
......

image.gif

🎗️就像古代最早出现的印刷术那样,使用一个模板可以去除掉那些大量并重复的工作。落实到语言中则诞生了模板(泛型编程)

1.函数模板

1.1使用

🎗️想要将这个函数定义成模板只需要在函数上加上这句话:template<class T ...> 其中参数的个数取决于实际需要的个数

🎗️其中的 class 还可以使用 typename 替换,二者都是定义模板参数关键字,区别不大,但是不可以使用 struct

🎗️这样子,我们便可以使用模板对上面交换函数进行修改

template<class T>
void swap(T& x, T& y)
{
  T tmp = x;
  x = y;
  y = tmp;
}

image.gif

🎗️我们可以将这个 T 想象成一个抽象的数据类型,他具体是什么我们不知道,但之后这个 T 会自己进行推演并转化成传入的类型

1.2实现逻辑

🎗️让我们思考一下,以下两次 swap 调用的是同一个函数吗?

template<class T>
void swap(T& x, T& y)
{
  T tmp = x;
  x = y;
  y = tmp;
}
int main()
{
  int a = 5, b = 6;
  double c = 5.5, d = 6.6;
  swap(a, b);
  swap(c, d);
  return 0;
}

image.gif

🎗️通过查看汇编,我们可以发现,其中调用的函数地址并不相同,即调用了两个不同的函数。


🎗️我们曾经将类比作蓝图,对象比作楼房。其实模板也是一样的,它会根据传入参数的不同类型进行推演,之后再进行实例化,生成不同版本的代码。因此不同类型的参数调用的函数并不是同一份

🎗️本质上不同类型的函数还是要实现一份的,但使用模板就将实例化这个重复的工作交给了编译器,由编译器代我们实现。

1.3实例化

🎗️用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化显式实例化

    • 隐式实例化:让编译器根据实参推演模板参数的实际类型。
    • 显式实例化:在函数名后的<>中指定模板参数的实际类型。

    🎗️若模板中只有一个数据类型,用两个类型的参数进行调用,编译器不知道该推演成哪个类型,便会出现歧义


    🎗️可以传参时强制类型转换,使其满足隐式实例化。也可以指定模板参数的实际类型,让参数发生隐式类型转换,使其满足显式类型转换


    1.4匹配规则

    🎗️一个非模板函数和一个同名的函数模板可以同时存在,那么在这种情况下会调用哪一个函数呢?

    template<class T>
    int add(const T& x,const T& y)
    {
      return x + y;
    }
    int add(int x, int y)
    {
      return x + y;
    }
    int main()
    {
      int a = 5, b = 6;
      add(a, b);
      return 0;
    }

    image.gif

    🎗️为了节约程序开销,编译器会优先选择成本较低的参数更加匹配的的函数进行调用。

    2.类模板

    2.1使用

    🎗️类模板的定义与函数模板类似,根据需要定义任意数量的模板参数,之后便可以使用模板参数作为抽象的数据类型到类中。

    template<class T>
    class A
    {
    public:
      A(T a = 1)
        :_a(a)
      {}
    private:
      T _a;
    };
    int main()
    {
      A<int> a1;
      return 0;
    }

    image.gif

    🎗️类模板中函数放在类外进行定义时,需要加模板参数列表

    template<class T>
    class A
    {
    public:
      A(T a = 1)
        :_a(a)
      {}
      ~A();           //类中声明函数
    private:
      T _a;
    };
    template<class T>   //需加上函数参数列表
    A<T>::~A()          //类外定义函数
    { 
      _a = 0;
    }
    int main()
    {
      A<int> a1; 
      return 0;
    }

    image.gif

    🎗️在实例化之前,当前模板类并不能算作一个真正的类,只是编译器根据被实例化的类型生成具体类的模具

    实例化

    🎗️与函数模板实例化不同,类模板实例化时需要在类模板名字后加上 <>,<>中放的是实例化的类型。因为编译器无法推演出其中的类型应该是如何对应的,因此需要手动指定

    A是类名,A<int>才是类型

    image.gif

    🎗️好了,今天模板基础内容的讲解到这里就结束了,如果这篇文章对你有用的话还请留下你的三连加关注。

    目录
    相关文章
    |
    1月前
    |
    程序员 C++
    C++模板元编程入门
    【7月更文挑战第9天】C++模板元编程是一项强大而复杂的技术,它允许程序员在编译时进行复杂的计算和操作,从而提高了程序的性能和灵活性。然而,模板元编程的复杂性和抽象性也使其难以掌握和应用。通过本文的介绍,希望能够帮助你初步了解C++模板元编程的基本概念和技术要点,为进一步深入学习和应用打下坚实的基础。在实际开发中,合理运用模板元编程技术,可以极大地提升程序的性能和可维护性。
    |
    2月前
    |
    安全 编译器 C++
    C++一分钟之-编译时计算:constexpr与模板元编程
    【6月更文挑战第28天】在C++中,`constexpr`和模板元编程用于编译时计算,提升性能和类型安全。`constexpr`指示编译器在编译时计算函数或对象,而模板元编程通过模板生成类型依赖代码。常见问题包括误解constexpr函数限制和模板递归深度。解决策略包括理解规则、编写清晰代码、测试验证和适度使用。通过实战示例展示了如何使用`constexpr`计算阶乘和模板元编程计算平方。
    50 13
    |
    1月前
    |
    存储 编译器 C++
    【C++】详解C++的模板
    【C++】详解C++的模板
    |
    6天前
    |
    编译器 C++
    【C++】模板初级
    【C++】模板初级
    |
    6天前
    |
    安全 编译器 C++
    【C++】模板进阶
    【C++】模板进阶
    |
    30天前
    |
    编译器 C++ 容器
    C++一分钟之-可变模板参数与模板模板参数
    【7月更文挑战第21天】C++的模板实现泛型编程,C++11引入可变模板参数和模板模板参数增强其功能。可变模板参数(如`print`函数)用于处理任意数量的参数,需注意展开参数包和递归调用时的处理。模板模板参数(如`printContainer`函数)允许将模板作为参数,需确保模板参数匹配和默认值兼容。这些特性增加灵活性,但正确使用是关键。
    32 4
    |
    1月前
    |
    安全 编译器 C++
    C++一分钟之-模板元编程实例:类型 traits
    【7月更文挑战第15天】C++的模板元编程利用编译时计算提升性能,类型traits是其中的关键,用于查询和修改类型信息。文章探讨了如何使用和避免过度复杂化、误用模板特化及依赖特定编译器的问题。示例展示了`is_same`类型trait的实现,用于检查类型相等。通过`add_pointer`和`remove_reference`等traits,可以构建更复杂的类型转换逻辑。类型traits增强了代码效率和安全性,是深入C++编程的必备工具。
    42 11
    |
    1月前
    |
    Java 编译器 Linux
    【c++】模板进阶
    本文详细介绍了C++中的模板技术,包括非类型模板参数的概念、如何使用它解决静态栈的问题,以及模板特化,如函数模板特化和类模板特化的过程,以提升代码的灵活性和针对性。同时讨论了模板可能导致的代码膨胀和编译时间增加的问题。
    21 2
    |
    1月前
    |
    C++ 开发者
    C++一分钟之-编译时计算:constexpr与模板元编程
    【7月更文挑战第2天】C++的`constexpr`和模板元编程(TMP)实现了编译时计算,增强代码效率。`constexpr`用于声明编译时常量表达式,适用于数组大小等。模板元编程则利用模板进行复杂计算。常见问题包括编译时间过长、可读性差。避免方法包括限制TMP使用,保持代码清晰。结合两者可以解决复杂问题,但需明确各自适用场景。正确使用能提升代码性能,但需平衡复杂性和编译成本。
    57 3
    |
    1月前
    |
    编译器 C语言 C++
    【C++】模板初阶(下)
    C++的函数模板实例化分为隐式和显式。隐式实例化由编译器根据实参推断类型,如`Add(a1, a2)`,但`Add(a1, d1)`因类型不一致而失败。显式实例化如`Add&lt;double&gt;(a1, d1)`则直接指定类型。模板函数不支持自动类型转换,优先调用非模板函数。类模板类似,用于创建处理多种数据类型的类,如`Vector&lt;T&gt;`。实例化类模板如`Vector&lt;int&gt;`和`Vector&lt;double&gt;`创建具体类型对象。模板使用时,函数模板定义可分头文件和实现文件,但类模板通常全部放头文件以避免链接错误。