Skip to content

Latest commit

 

History

History
123 lines (86 loc) · 2.81 KB

File metadata and controls

123 lines (86 loc) · 2.81 KB

条款01:理解模板类型推导

函数模板大致形如:

template <typename T>
void f(ParamType param);

调用形如:

f(expr);

在编译期,编译器会通过expr推导T和ParamType的类型,ParamType通常包含一些修饰词,如 const 或引用等限定词。

T 的类型推导结果不仅依赖expr的类型,还依赖ParamType的形式。需要分三种情况讨论。

情况1:ParamType是个指针或引用,但不是万能引用

类型推导会这样运作:

  1. 若expr有引用类型,则先将引用忽略。
  2. 然后对expr的类型和ParamType的类型执行模式匹配,来决定T的类型。

例如,模式如下:

template <typename T>
void f(T& param);

又声明了如下变量:

int x = 27;
const int cx = x;
const int& rx = x;

类型推导结果如下:

expr T ParamType
x int int&
cx const int const int&
rx const int const int&

形参是右值引用或指针的类型推导运作方式是完全相同的。

情况2:ParamType是个万能引用

  • 如果expr是个左值,T 和ParamType都会被推导为左值引用,这是在模板类型推到中 T 被推导为引用的唯一情形。
  • 如果expr是个右值,则应用情况1的常规规则。

例如:

template <typename T>
void f(T&& param);
expr T ParamType
x int& int&
cx const int& const int&
rx const int& const int&
27 int int&&

情况3:ParamType既非指针也非引用

即按值传递:

template <typename T>
void f(T param);
  • 若expr具有引用类型,则忽略其引用部分。
  • 忽略expr的引用性后,去除expr的cv限定。
expr T ParamType
x int int
cx int int
rx int int

数组实参

有些情况下数组会退化为指向首元素的指针。函数无法正确声明真正的数组类型的形参,但它们却能够将形参声明为数组的引用。如果我们按引用传递实参:

template <typename T>
void f(T& param);

然后,向其传递一个数组

const char* name[] = "J. P. Briggs";
f(name);

在这种情况下,T会被推导为 const char [13],而param被推导为const char (&)[13]

函数实参

函数类型也同样会退化为函数指针。

void someFunc(int, double);

template <typename T>
void f1(T param);

template <typename T>
void f2(T& param);
函数 param类型
f1 void (*)(int, double)
f2 void (&)(int, double)