c++ 模板

Posted lvmf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++ 模板相关的知识,希望对你有一定的参考价值。

模板Template)——支持将类型作为参数的程序设计。允许定义类,函数或类型别名时将类型或参数作为参数

  指C++程序设计语言中的函数模板与类模板,是一种参数化类型机制,大体对应于java和C#中的泛型,但也有一些功能上的显著差异(C++模板支持后两者没有明确对应的模板模板参数和模板非类型参数,但不支持Java的通配符以及C#的泛型类型约束)。模板是C++的泛型编程中不可缺少的一部分。

多重继承与运算符重载。C++的标准函数库提供的许多有用的函数大多结合了模板的概念,如STL以及iostream。

 

模板的声明与定义

  模板定义以关键字template开始,后接模板形参表(template parameter list),模板形参表是用尖括号<>括住的一个或者多个模板形参的列表,形参之间以逗号分隔。模板形参可以是表示类型的类型形参(type parameter),也可以是表示常量表达式的非类型形参(non-type parameter),非类型形参跟在类型说明符之后声明。类型形参跟在关键字class或typename之后声明。模板形参可以给出默认值(default arguments for template parameters)。

模板的非类型形参

模板的非类型形参(template non-type parameter)允许为下述形式:

  • 整型或枚举型
  • 到对象的指针或函数指针
  • 到对象的引用或函数引用
  • 成员指针

 模板的非类型参数被声明为数组或函数的,将被转换为指针或函数指针。例如:

1 template<int a[4]> struct A { };
2  template<int f(int)> struct B { };
3  int i;
4  int g(int) { return 0;}
5  A<&i> x;
6  B<&g> y;

 

模板的非类型形参允许用const或volatile限定(而模板的类型形参是不允许cv限定的)。模板的非类型形参是不允许声明为浮点型、class类型、void型。

模板的模板参数

类模板的模板参数允许是另外一个类模板,这称为模板的模板参数(template template parameter),也译作“模板参数模板”。函数模板不允许有模板的模板参数。例如:

1 template<template <class T> class X> class A { }; //类模板A的第二个参数是另外一个类模板X
2 template<class T> class B { };
3 A<B> a; //模板A的实际使用。其中的B是模板的模板实参(template template argument)

 

模板参数的默认值

模板形参可以给出默认值(default arguments for template parameters)。如果一个模板参数给出了默认值,那么模板形参列表中在其后声明的模板参数都应该给出默认值。例如:

template<class T = char, class U, class V = int> class X { }; //编译出错,或者给出U的默认值,或者不给出T的默认值

 

一个模板的各次声明给出的模板参数的默认值可以累积其效果。例如:

template<class T, class U = int> class A;
template<class T = float, class U> class A;
template<class T, class U> class A {
  public:
     T x;
     U y;
};
A<> a; //a.x is float, and the type of a.y is int

 

但是如果交换本示例第一行与第二行的次序,将编译报错。因为如果第一个模板参数T有了默认值,此时编译器必须已经知道其后的第二个模板参数U的默认值。

在同一个作用域(scope)中,不能对同一个模板的同一个参数多次声明其默认值。例如:

template<class T = char> class X;
template<class T = char> class X { };//编译报错。如果在本行中不给出模板参数T的默认值将编译通过

 

模板参数的作用域为从其声明之处至该模板的定义结束之处。因此可以使用一个模板参数作为其后声明的其他模板参数的一部分或默认值。例如:

template<class T = char> class X;
template<class T = char> class X { };//编译报错。如果在本行中不给出模板参数T的默认值将编译通过

 

变量模板

变量模板(variable template)是C++14引入的新的一个种类的模板。可用于在名字空间作用域声明一个变量。例如:

1 template<class T>
2 constexpr T pi = T(3.1415926535897932385);  // variable template
3 template<class T>
4 T circular_area(T r) // function template
5 {
6    return pi<T> * r * r; // pi<T> is a variable template instantiation
7 }

 

可以在类作用域声明一个静态数据成员:

template<class T>
constexpr T pi = T(3.1415926535897932385);  // variable template
template<class T>
T circular_area(T r) // function template
{
   return pi<T> * r * r; // pi<T> is a variable template instantiation
}

 

类的静态数据成员模板,也可以用类模板的非模板数据成员来实现:

struct limits {
   template<typename T>
   static const T min; // declaration of a static data member template
};
template<typename T> const T limits::min = { }; // definition of a static data member template
template<class T> class X {
    static T s; // declaration of a non-template static data member of a class template
};
template<class T> T X<T>::s = 0; // definition of a non-template data member of a class template

 

变量模板不能用作模板的模板参数(template template arguments)。

模板的使用

使用模板时,可以在模板名字后面显式给出用尖括号括住的模板实参列表(template argument list)。对模板函数或类的模板成员函数,也可不显式给出模板实参,而是由编译器根据函数调用的上下文推导出模板实参,这称为模板参数推导

如果模板参数使用其默认值,则在模板实参列表中可以忽略它。如果所有的模板参数都使用了默认值,模板实参列表为空,但仍然必须写出成对的尖括号。例如:

1 template<class T = int> class X { };
2 X<> a; //编译通过
3 X b;   //编译报错

 

对于作为类型的模板实参,不允许是局部类型(local type)、无链接性的类型(type with no linkage)、无名类型(unnamed type)或包括了这三种情形的复合类型。但C++11以及允许本地类型作为模板实参。

 

以上是关于c++ 模板的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段2——.vue文件的模板

VSCode自定义代码片段(vue主模板)

这些 C++ 代码片段有啥作用?

有趣的 C++ 代码片段,有啥解释吗? [复制]

以下代码片段 C++ 的说明

C++ 代码片段执行