C++ Templates (1.2 模板实参推断 Template Argument Deduction)

时间:2022-05-28 15:06:10

返回完整目录

1.2 模板实参推断 Template Argument Deduction

当调用函数模板(如max())时,模板参数由传入的实参决定。如果传递两个int给参数类型T,C++编译器推断出T的类型为int。

然而,T可能是类型的一部分。比如说,如果声明max()使用常量引用(const reference):

template <typename T>
T max(T const& a, T const& b)
{
return b < a ? a : b;
}

并且传递int类型的参数,T同样被推断为int类型,因为函数参数与int const&完全匹配。

类型推断时类型转换

在类型推断中,自动类型转换受到限制:

  • 当声明调用参数(call parameter)为引用类型,甚至一般的转换也不能用于类型推断。两个声明为同一个模板参数(template parameter)T类型的实参必须严格匹配。(Two arguments declared with the same template parameter T must match exactly)。

  • 当声明调用参数为值类型,只有退化(decay)的普通转换才被支持。const或者volatile等限制将被忽略,引用类型转化为被引用的类型,原始数组(raw array)或者函数被转化为对应的指针类型。两个被声明为同一个模板参数T类型的实参,其退化类型必须匹配。

比如:

template <typename T>
T max(T a, T b);
...
int i = 17;
int const c = 42;
max(i, c); //OK: T 被推断为int
max(c, c); //OK: T 被推断为int
int& ir = ;
max(i, ir); //OK: T被推断为int
int arr[4];
max(&i, arr); //OK: T被推断为int*

然而,以下调用将引发错误:

max(4, 7.2);      //Error:T 可能被推断为int或者double
std::string s;
max("hello", s); //Error: T 可能被推断为char const[6]或者std::string

有三种方法来处理此类错误:

  1. 转换实参使得两个参数得以匹配:
max(static_cast<double>(4), 7.2);
  1. 显式指定或者限制T的类型来防止编译器进行类型推断:
max<double>(4, 7.2);
  1. 将两个参数指定为不同的类型。

第1.3节将围绕该方案,第7.2节和第15章将详细讨论类型推断过程中的类型转换规则。

默认实参的类型类型推断 Type Deduction for Default Arguments

默认调用实参(default call arguments)不能用于类型推断,比如:

template <typename T>
void f(T = "");
...
f(1); //OK: T推断为int,因此它将调用f<int>(1)
f(); //Error: 无法推断T类型

为了支持这一情形,必须声明默认模板实参(default argument for the template parameter),这将在1.4节中讨论:

template <typename T = std::string>
void f(T = "");
...
f(); //OK