1. 模板函数参数类型推导
有三个关键点需要注意:
- 每个实参独立推导模板参数类型。
- 在每个实参的推导过程中,允许两种隐式转换,单向的非low-level const向low-level const转换(top-level const和精确匹配无异自不必说)和array和function向对应的指针类型的转换。
- 最终对同一个模板参数推导出的类型必须相同。
对于这三点的印证,可以看一下这个chatgpt的问答以供参考。
问题如下:
根据你掌握的C++标准相关的知识回答这个问题:
void func(T, T);
template<class T>
void func2(const T *, const T *);
int a, b;
int *pa = &a; const int *pb = &b;
func(pa, pb);
func2(pa, pb);
判断1: 对于func来说,推断参数T为const int *即可,这样pa隐式转换为const int *即可,只涉及low-level const conversion。
判断2: 对于func2来说,将T推断为int即可,这样pa隐式转换为const int *即可,只涉及low-level const conversion。
请分析两个判断是否正确
问答如下:
对 func 的调用
模板定义为:
template<class T>
void func(T, T);
调用时传入的参数类型分别为:
第一个参数:类型为 int*
第二个参数:类型为 const int*
模板参数 T 的推导过程要求两个参数必须推导出相同的 T。对第一个参数推导得到 T = int*;对第二个参数推导得到 T = const int*。由于 int* 与 const int* 不完全相同(指针指向的类型 cv 限定不同),模板参数推导不能通过将 T 统一为 const int* 来“补救”这一不匹配,因为模板参数推导过程中不考虑隐式转换(包括 low-level const 转换)。因此,调用 func(pa, pb) 会导致模板参数推导失败。
判断1中所述“对于 func 来说,推断参数 T 为 const int* 即可”是不正确的。
对 func2 的调用
模板定义为:
template<class T>
void func2(const T *, const T *);
调用时的参数仍然是:
第一个参数:类型为 int*
第二个参数:类型为 const int*
对第一个参数进行推导:要求参数类型 const T* 与 int* 匹配。推导时将指针解引用,得到要求 const T 与 int 匹配,此时 T 被推导为 int(推导过程中忽略了目标类型的 const 限定,因为它是 low-level 限定,需要在调用时通过隐式转换来补上)。
对第二个参数:要求 const T* 与 const int* 匹配,同样推导得到 T = int。
因此,两处均一致地推导出 T = int。推导完成后,函数参数类型为 const int*,对于第一个参数 int* 允许隐式转换为 const int*(low-level const 转换),对于第二个参数正好匹配。
判断2中所述“对于 func2 来说,将 T 推断为 int 即可”是正确的。
总结
判断1:错误。对于 func(pa, pb),模板参数 T 无法同时满足 int* 和 const int* 的要求,不能仅通过隐式转换统一为 const int*。
判断2:正确。对于 func2(pa, pb),T 被一致推导为 int,调用中 int* 隐式转换为 const int*,仅涉及 low-level const 转换。