c++模板函数,c++模板元编程

  c++模板函数,c++模板元编程

  Yyds干货库存

  @toc

  现在我们来打开C和C的区别,模板。众所周知,C中没有标准的数据库,但是C中却存在STL,这是因为C支持泛型编程,这是我们今天需要了解的重点。今天的模板是初级阶段。我们来简单了解一下。

  什么是泛型?所谓泛型,不再是针对某一种类型,而是着眼于广泛的类型。

  这句话你可能不太懂。我们用一个简单的例子来解释一下。在C语言中,我们需要写一个简单的两个数的交换。我们需要考虑这两个数的类型,写不同的函数。而且C语言不支持函数重载,不方便。然而,使用泛型是不同的。我们可以用一个通用函数来解决它。

  可能你还是看不懂下面这段代码。我们只需要先了解这个东西,后面会一一给你解释。

  模板类T

  无效交换(T左,T右)

  T temp=左;

  左=右;

  右=temp

  }

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

  我们都知道活字印刷,一个通用的功能相当于一个模板。我们需要什么类型就会给编译器,编译器会通过我们给的类型的模板自动写出这个函数。

  模板主要分为两类。

  通用关键字

  c提供了两个关键字来帮助我们学习模板,下面的代码是。

  这句话意味着我们声明下面的函数或类是一个模板,而T1,T2.表示数据类型。我们需要在使用的时候告诉编译器,后面会讲到。

  模板类型名T1,类型名T2.

  在这里,我要声明,在一些旧语法中,我们也可以用class代替typename,但现在我们认为它们的功能是一样的。

  #函数模板

  函数模板代表一系列函数。函数模板与类型无关,使用时参数化,根据实参类型生成函数的特定类型版本。

  模板的格式

  功能模板就像一个模子,它没有地址。当我们传入参数时,编译器会通过模板自动推出一个函数,那么这个函数就会有一个地址,但是模具没有变。

  模板类型名T1,类型名T2,键入名称Tn

  返回值函数名(参数列表)

  }

  我们先来看看函数模板,还是以交换函数为例。后面还有很多例子。

  #包括iostream

  使用STD:cout;

  使用STD:endl;

  模板类T

  无效交换(T左,T右)

  T temp=左;

  左=右;

  右=temp

  int main()

  int a=1;

  int b=2;

  互换(a,b);

  cout a= a

  cout b= b endl

  返回0;

  }

  模板实例化

  让我们先解决一个不太难的问题。我们是通过提供不同的参数类型来调用同一个函数吗?这肯定不是真的。我们先来看看现象。

  int main()

  int a=1;

  int b=2;

  双c=1.0

  双d=2.0

  互换(a,b);

  cout ========= endl

  互换(c,d);

  返回0;

  }

  这就是模板的实例化,编译器通过我们给定的数据类型(或者自动派生)自动生成相应的函数。

  在这里告诉你,以后我们不需要用C写交换函数了。是用C标准库写的。

  隐式实例化

  模板类T

  T添加(T a,T b)

  返回a b;

  }

  这是一个模板,为我们提供一个编译器。一旦我们决定调用add函数,这里就会发生一些事情。

  我们传入了参数,编译器会通过参数自动推导出数据类型,然后自动生成相应的函数。

  显式实例化

  现在我们有一个问题。编译器一定会通过参数推导出类型吗?看下面这个函数。

  我们传入的参数类型已经确定,那么告诉我如何确定返回值的类型。

  模板类T

  T func(int n)

  返回n;

  }

  这里需要以现在的形式调用这个函数。编译器不知道,但是我们可以知道。看下面的用法。

  模板类T

  T func(int n)

  返回n;

  int main()

  int ret=func int(10);

  cout ret endl

  返回0;

  }

  显式实例化和隐式实例化的优先级

  现在有了两个实例化,我想知道如果同时存在,哪一个起决定作用?

  答案是显而易见的,显示器起着决定性的作用。

  模板类T

  T函数

  返回n;

  }

  模板参数有默认值吗?

  是的,也就是说,我们可以使用提供给模板的默认值,但是这个默认值是一个类型。如果看一下用法,会发现和函数参数的用法很像。

  模板类T=int

  T func(int n)

  返回n;

  int main()

  int ret=func(10);

  cout ret endl

  返回0;

  }

  声明和定义可以分开吗?

  这个问题需要分开来看。

  既然模板可以看作一个函数,那么可以单独声明和定义吗?我们都需要添加模板关键字。

  注意,我们需要知道一件事。模板不支持两个文件中的声明和定义,会有链接错误。需要到了高级阶段再说具体原因。

  很多地方我们把模板声明和定义放在同一个文件里,有的把这个文件的后缀写成。默认情况下,hpp可以告诉我们这是一个带有模板的头文件,但这不是必需的。

  以下是报告错误原因的简要说明。

  我们可以这样理解。在重定义文件中,编译器不知道T的类型,也就是说,编译器不会把符号存储在符号表中,链接时也找不到。这里有一个令人沮丧的方法,它使用显示实例化来指定。

  也就是说,在定义文件中显示使用模板,但这令人沮丧。你必须展示所有你用过的。比如使用int类型很麻烦,但是对其他人来说也是必须的。最好不要把它们分成两个文件。

  模板参数的匹配规则

  我们有麻烦了。我们先来分析一下以下两者是否可以同时存在。是的,模板不是一个函数。

  模板类T

  T加法(T左,T右)

  cout T add endl

  向左向右返回;

  int add(int left,int right)

  cout int add endl

  向左向右返回;

  }

  既然能存在,这个地方又有一个问题。编译器先调用哪个?

  int main()

  int x=1;

  int y=2;

  add(x,y);

  返回0;

  }

  直接看现象,可以发现先调用函数无可厚非,而不是函数模板。既然是现成的,何必自己去生成呢?

  那么我们如何让编译器调用模板呢?这里还有一个方法,使用显式实例化。

  我们先来了解一下类模板。我们发现它们和普通的类没什么区别,就是把对应的具体数据类型改成了泛型。

  模板类T

  类堆栈

  公共:

  stack(int cap=4);

  ~ Stack();

  void push();

  私人:

  T * elme

  size_t大小;

  int cap

  };

  类别模板格式

  包括类定义和成员函数定义,我们分开来说。

  先说我们现在拥有的最基本的东西。

  但是我们的成员函数的声明和定义并没有分开,所以我们可以按照下面的方法来做。

  班级学生

  公共:

  学生()

  _ cap=4;

  _ elem=new T[_ cap];

  _ size=10

  ~ Student();

  私人:

  T * elem

  szie _ t _ size

  szie _ t _ cap

  };

  但是如果成员函数的声明和定义是分开的,我们就做不到这一点。

  可以说每个成员函数都会有template\ class T和Student\ T:这是编译器所需要的。

  模板类T

  班级学生

  公共:

  学生();

  ~ Student();

  私人:

  T * elem

  szie _ t _ size

  szie _ t _ cap

  模板类T

  学生T:学生()

  _ cap=4;

  _ elem=new T[_ cap];

  _ size=10

  模板类T

  学生T:~学生()

  如果(元素)

  删除[]elem;

  _ size=0;

  _ cap=0;

  }

  类实例化

  类模板实例化不同于函数模板实例化。类模板实例化需要后跟类模板名称,然后可以将实例化的类型放入。类模板名不是真正的类,但实例化的结果是真正的类。

  我们用的时候,记得显示实例化就行了。我们来看看用法。

  int main()

  学生char学生;

  返回0;

  }

  模板参数的再分析

  我们需要理解模板参数。这里我们需要思考一个问题。为什么下面的代码会报告错误?

  模板类T

  T相加(左常数,右常数)

  cout T add endl

  向左向右返回;

  int main()

  添加(1,2.2);

  返回0;

  }

  这是因为编译器无法通过给定分部数据推导出参数的类型、一个int、一个double,编译器会因为矛盾而给出错误。

  我们可以通过以下方法解决这个问题。

  默认模板参数

  这个我们可以和默认函数一起理解,思路是一样的。

  模板类别K,类别V

  void函数()

  cout sizeof(K)endl;

  cout sizeof(V)endl;

  int main()

  func int,double

  返回0;

  }

  如果我们这样做呢?

  int main()

  函数int

  返回0;

  }

  这就要求默认模板参数的存在,并且我们可以通过全部或部分默认来保证程序的正确。

  模板类K,类V=char

  void函数()

  cout sizeof(K)endl;

  cout sizeof(V)endl;

  int main()

  函数int

  返回0;

  }

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • office2010激活密钥大全 怎么永久激活office2010
  • project2010产品密钥免费_project2010激活密钥永久激活码
  • c语言调用退出函数 c语言退出整个程序怎么写
  • c语言中怎么给函数初始化 c语言的初始化语句
  • c语言编写函数计算平均值 c语言求平均函数
  • chatgpt是什么?为什么这么火?
  • ChatGPT为什么注册不了?OpenAI ChatGPT的账号哪里可以注册?
  • OpenAI ChatGPT怎么注册账号?ChatGPT账号注册教程
  • chatgpt什么意思,什么是ChatGPT ?
  • CAD中怎么复制图形标注尺寸不变,CAD中怎么复制图形线性不变
  • cad中怎么创建并使用脚本文件,cad怎么运行脚本
  • cad中快速计算器的功能,cad怎么快速计算
  • cad中快速修改单位的方法有哪些,cad中快速修改单位的方法是
  • cad中心点画椭圆怎么做,cad轴测图怎么画椭圆
  • CAD中常用的快捷键,cad各种快捷键的用法
  • 留言与评论(共有 条评论)
       
    验证码: