12. C++模板

简介: 12. C++模板

什么是模板

模板编程也可以叫做泛型编程,忽略数据类型的一种编程方式

//求最值问题
int  Max(int a,int b)
{
  return a>b?a:b;    
}
double Max(int a,int b)
{
  return a>b?a:b;        
}
string Max(string a,string b)
{
  return a>b?a:b;        
}
//引入模板编程
template <typename  type>   //告诉编译器,下面会用到一个未知类型叫做type
type Max(type a,type b)
{
  return a>b?a:b;        
}

模板代码

#include <iostream>
using namespace std;
template <typename type> 
type Max(type a, type b) 
{
  return a > b ? a : b;
}
//typename 可以用class 替换
template <class T>
void print(T data) 
{
  cout << data << endl;
}
int main() 
{
  //隐式调用
  cout << Max(1, 2) << endl;
  cout << Max(1.1, 2.2) << endl;
  //string 和char* 有区别
  cout << Max(string("1ILoveyou"), string("2IMissyou")) << endl;
  //显示调用 <>传类型的参数
  cout << Max<int>(1, 2) << endl;   //type=int  a=1 b=2
  cout << Max<string>(string("1"), string("2")) << endl;
  cout << Max<double>(1.2, 1.3) << endl;
  return 0;
}

函数模板

函数模板重载问题

  • 函数模板和普通函数
  • 函数模板和函数模板
#include <iostream>
using namespace std;
//No.1 模板与普通函数
int Max(int a, int b) 
{
  cout << "普通函数..." << endl;
  return a > b ? a : b;
}
template <class T>
T Max(T a, T b) 
{
  cout << "模板" << endl;
  return a > b ? a : b;
}
//No.2 模板与模板
template <class type1,class type2,class type3>
void print(type1 one, type2 two, type3 three) 
{
  cout << "三只" << endl;
}
template <class type1,class type2>        //type1=int type2=double
void print(type1 one, type1 two, type2 tow)     //int int double
{
  cout << "两只" << endl;
}
template <class type>
void print(type one, type two, type three) 
{
  cout << "一只" << endl;
}
int main() 
{
  cout << Max<int>(1, 2) << endl;   //显式调用,百分百调用模板
  cout << Max(1, 2) << endl;      //优先调用类型确定的函数
  cout << "显示调用" << endl;
  print<int, double, string>(1, 1.1, string("23"));
  print<int, double>(1, 1, 1.22);
  print<int>(1, 2, 3);
  cout << "隐式调用" << endl;
  print(1, 1, 2);           //需要传参越少先调用
  print(1, 1, string("sdsd"));    
  print(1, 1.11, string("sdsd"));   //只有一种选择
  return 0;
}

类成员函数是函数模板

//这种不叫做模板类型
class  MM 
{
public:
  template <class T>
  void print(T data) 
  {
    cout << data << endl;
  }
protected:
};
int main()
{
    MM mm;
  mm.print(1);
  mm.print<string>("string");
  return 0;    
}

函数模板缺省

函数模板缺省和函数参数的缺省是一样的规则

//函数模板缺省
template <class type1,class type2=string>
void printData(type1 one, type2 two) 
{
  cout << one << endl;
  cout << two << endl;
}
int main()
{
    printData<int, double>(1, 1.22);
  printData<int>(1, string("dsfsdf"));
    return 0;
}

函数模板传常量

//函数模板传常量
template <class T,size_t size>
void printArray(T* array) 
{
  for (int i = 0; i < size; i++) 
  {
    cout << array[i] << " ";
  }
  cout << endl;
}
int main()
{
  int num[3] = { 1,2,3 };
  printArray<int, 3>(num);
  //下面代码报错
  //int length = 3;
  //printArray<int, length>(num);
  string str[4] = { "sdds","sd","sdsd" ,"sdds"};
  printArray<string, 4>(str);
    return 0;
}

类模板

类模板的基础

  • 怎么写类模板
  • 类模板不是一个完整类型,所以任何用到类名的地方都需要用类名<未知类型>的方式使用
  • 怎么去使用类模板,类模板必须采用显式调用方式
  • 类模板在多文件中不能分开写
  • 可以写在.hpp文件中(声明和实现都在一起)
#include <iostream>
#include <map>
using namespace std;
template <class type1,class type2>
struct my_pair 
{
  type1 first;    //键
  type2 second;   //值
  my_pair(type1 first, type2 second) :first(first), second(second) {}
  my_pair() = default;
};
template <class type1,class type2>
my_pair<type1, type2> my_make_pair(type1 one, type2 two) 
{
  return my_pair<type1, type2>(one, two);
}
template <class type1,class type2>
class Test 
{
public:
  Test(type1 one, type2 two) :one(one), two(two) 
  {
  }
  void printTest();
protected:
  type1 one;
  type2 two;
};
template <class type1, class type2>
void Test<type1,type2>::printTest() 
{
  cout << one << " " << two << endl;
}
template <class type1,class type2>
class Data :public Test<type1,type2> 
{
public:
  Data(type1 one, type2 two) :Test<type1, type2>(one, two) 
  {
  }
protected:
};
int main() 
{
  my_pair<int,int> pairData = { 1,2 };
  cout << pairData.first << " " << pairData.second << endl;
  my_pair<int, string>* p = new my_pair<int, string>;
  p->first = 12;
  p->second = "sdsd";
  cout << p->first << " " << p->second << endl;
  
  Data<int, int>  data(1, 2);
  data.printTest();
  //标准库中的pair类型
  pair<int, string> pD(1, "ILoveyou");
  cout << pD.first << " " << pD.second << endl;
  pair<int, string> testData = make_pair<int, string>(1, "sdfsdf");
  my_pair<int, string> my_testData =my_make_pair<int, string>(1, "sdfsdf");
  return 0;
}

类模板特化问题

  • 局部特化
  • 完全特化

特化的目的是为了适应不同数据的不同处理

#include <iostream>
using namespace std;
template <class _Ty1,class _Ty2,class _Ty3>
class Data
{
public:
  Data(_Ty1 one, _Ty2 two, _Ty3 three) :one(one), two(two), three(three) {}
  void printData()
  {
    cout << (one + two + three) << endl;
  }
private:
  _Ty1 one;
  _Ty2 two;
  _Ty3 three;
};
//局部特化
//两个数据,打印两数之差
template <class _Ty1,class _Ty2>
class Data<_Ty1,_Ty1,_Ty2> 
{
public:
  Data(_Ty1 one, _Ty2 two) :one(one), two(two){}
  void printData()
  {
    cout << (one -two) << endl;
  }
private:
  _Ty1 one;
  _Ty2 two;
};
//只有一个数据,打印数据
template <class _Ty1>
class Data<_Ty1,_Ty1,_Ty1>
{
public:
  Data(_Ty1 one) :one(one){}
  void printData()
  {
    cout << one << endl;
  }
private:
  _Ty1 one;
};
//完全特化
template <>
class Data<string, string, string> 
{
public:
  Data(string one,string two,string three):one(one),two(two),three(three)
  {
  }
  void printData();
private:
  string one;
  string two;
  string three;
};
void Data<string,string,string>::printData()
{
  cout << one << " " << two << " " << three << endl;
}
int main() 
{
  Data<int, int, int> data1(1);
  data1.printData();
  Data<int,int, double> data2(2, 1);
  data2.printData();
  Data<int, double, float> data3(1, 1.1, 1.2f);
  data3.printData();
  Data<string, string, string> data4("dsd","sdfd","sdfdsf");
  data4.printData();
  return 0;
}

模板操作自定义类型

  • 模板操作自定义关键点在于重载
#include <iostream>
#include <algorithm>
using namespace std;
class MM 
{
public:
  MM() = default;
  MM(string name, int age) :name(name), age(age) {}
  friend ostream& operator<<(ostream& out, const MM& object) 
  {
    out << object.name << " " << object.age;
    return out;
  }
private:
  string name;
  int age;
};
template <class _Ty>
void printData(_Ty data)
{
  cout << data << endl;
}
template <class _Ty1,class _Ty2,class _Ty3>
class Data
{
public:
  //_Ty1=MM, _Ty2=int, _Ty3=int
  Data(_Ty1 one, _Ty2 two, _Ty3 three) :one(one), two(two), three(three)
  {
  }
  void printData() 
  {
    cout << one << " " << two << " " << three << endl;
  }
private:
  _Ty1 one;
  _Ty2 two;
  _Ty3 three;
};
int main()
{
  printData(1);
  printData("string");
  MM mm = { "小芳",18 };
  printData(mm);
  Data<MM, int, int> data(MM("小芳",18),98,99);
  data.printData();
  Data<MM, MM, MM> mmData(MM("小芳", 18), MM("小芳", 18), MM("小芳", 18));
  mmData.printData();
  return 0;
}

模板嵌套模板

  • 关键点在于大家自己要清楚类型如何表示(类型是由类名<类型>表示一个类型)
#include <iostream>
using namespace std;
template <class _Ty1,class _Ty2,class _Ty3>
class Data 
{
public:
  Data(_Ty1 one, _Ty2 two, _Ty3 three) :one(one), two(two), three(three) {}
  void printData() 
  {
    cout << one << " " << two << " " << three << endl;
  }
  friend ostream& operator<<(ostream& out, Data<_Ty1, _Ty2, _Ty3>& object)
  {
    out << object.one << " " << object.two << " " << object.three;
    return out;
  }
protected:
  _Ty1 one;
  _Ty2 two;
  _Ty3 three;
};
template <class _Ty1, class _Ty2>
class Info
{
public:
  Info(_Ty1 one, _Ty2 two) :one(one), two(two) {}
  void printData()
  {
    cout << one << " " << two << endl;
  }
  //template <class _Ty1, class _Ty2>  类中实现不需要修饰了,会出现重定义问题
  friend ostream& operator<<(ostream& out, Info<_Ty1, _Ty2>& object)
  {
    out << object.one << " " << object.two << " ";
    return out;
  }
protected:
  _Ty1 one;
  _Ty2 two;
};
template <class _Ty1>
class Student
{
public:
  Student(_Ty1 one) :one(one) {}
  void printData() 
  {
    cout << one << endl;
  }
protected:
  _Ty1 one;
};
int main() 
{
  Data<int, int, int> data(1,1,1);  //Data<int, int, int>
  Info<int, int> info(1, 2);      //Info<int, int>
  
  Info<Data<int, int, int>, Data<string, string, string>>
    test1(Data<int, int, int>(1, 1, 1), Data<string, string, string>("ds", "sd", "sds"));
  //起别名
  using type1 = Data<int, int, int>;
  using type2 = Data<string, string, string>;
  //别名版本
  Info<type1, type2>test2(type1(1, 1, 1), type2("ds", "sd", "sds"));
  Data<Info<int, string>, Info<string, string>, Info<int, double>> 
    test3(Info<int, string>(1,"sd"), Info<string, string>("sdds","dsds"),Info<int, double>(1,1.11));
  test1.printData();
  test2.printData();
  test3.printData();
  Student<Data<Info<int, int>, Info<int, string>, Info<string, string>>> 
    stu(Data<Info<int, int>, Info<int, string>, Info<string, string>>
      (Info<int, int>(1,1), Info<int, string>(1,"sdsd"), Info<string, string>("sds","sdsd")));
  stu.printData();
  return 0;
}
目录
相关文章
|
2月前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
112 10
|
4月前
|
编译器 C++
【C++】——初识模板
【C++】——初识模板
【C++】——初识模板
|
21天前
|
安全 编译器 C++
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
36 4
|
21天前
|
算法 编译器 C++
【C++】模板详细讲解(含反向迭代器)
C++模板是泛型编程的核心,允许编写与类型无关的代码,提高代码复用性和灵活性。模板分为函数模板和类模板,支持隐式和显式实例化,以及特化(全特化和偏特化)。C++标准库广泛使用模板,如容器、迭代器、算法和函数对象等,以支持高效、灵活的编程。反向迭代器通过对正向迭代器的封装,实现了逆序遍历的功能。
31 3
|
5月前
|
程序员 C++
C++模板元编程入门
【7月更文挑战第9天】C++模板元编程是一项强大而复杂的技术,它允许程序员在编译时进行复杂的计算和操作,从而提高了程序的性能和灵活性。然而,模板元编程的复杂性和抽象性也使其难以掌握和应用。通过本文的介绍,希望能够帮助你初步了解C++模板元编程的基本概念和技术要点,为进一步深入学习和应用打下坚实的基础。在实际开发中,合理运用模板元编程技术,可以极大地提升程序的性能和可维护性。
|
24天前
|
编译器 C++
【c++】模板详解(1)
本文介绍了C++中的模板概念,包括函数模板和类模板,强调了模板作为泛型编程基础的重要性。函数模板允许创建类型无关的函数,类模板则能根据不同的类型生成不同的类。文章通过具体示例详细解释了模板的定义、实例化及匹配原则,帮助读者理解模板机制,为学习STL打下基础。
29 0
|
2月前
|
编译器 程序员 C++
【C++打怪之路Lv7】-- 模板初阶
【C++打怪之路Lv7】-- 模板初阶
18 1
|
2月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
53 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
2月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
84 2
|
2月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
42 2