C++模板类型推导疑问:int实参匹配const T&为何推导成功?
示例代码回顾
第一个示例
template<typename T> void f(T&) {}; int main(void){ const int i = 0; const int& r = i; f(r); }
推导逻辑:模板参数类型P = T&,实参类型A = const int。根据[temp.deduct.call]/3条款,若P是引用类型,则使用P引用的类型推导,即推导目标变为T,匹配const int,最终T = const int。
第二个示例
template<typename T> void g(const T&) {}; int main(void) { int i = 0; g(i); }
推导起点:P = const T&,A = int。按[temp.deduct.call]/3处理后,推导目标为const T,实参类型为int。
问题一解答
你的判断错误,T是可以正常推导的,不存在推导失败的情况。
核心原因:模板参数推导中,从非const限定类型到const限定类型的转换属于允许的匹配范畴,不会导致推导失败。根据C++11标准[temp.deduct.call]/4条款:
当推导模板参数时,对于作为函数参数的类型P和实参类型A,如果A的类型可以通过添加顶层const限定转换为P的类型,则推导会将模板参数调整为使得P与A的限定转换后的类型匹配。
具体到本例,推导目标是const T,实参是int,当T = int时,const T就是const int,而int可以隐式转换为const int(这是限定转换,属于模板推导允许的匹配项),因此推导成立,T可以确定为int。
你误以为“需要限定转换就无法推导”是混淆了模板推导的匹配规则和函数调用的隐式转换规则:模板推导只要求P的类型(经过规则调整后)能与A的类型通过允许的转换匹配,而限定转换是明确允许的推导匹配项。
问题二解答
g11.2.0的编译结果完全符合C标准:
当T推导为int时,模板实例化后的函数签名是g<int>(const int&),此时实参int i可以直接绑定到const int&类型的参数——这是C++中允许的隐式绑定(非const左值可以绑定到const左值引用),因此代码编译正常,实例化结果正确。
内容的提问来源于stack exchange,提问作者mada

