C++函数模板重载决议流程验证及相关问题咨询
重载决议是我学习C++过程中接触过的最复杂的机制,该内容理解难度较高,还请各位答疑时多多包涵。我在此准备了两个示例,尝试逐例梳理编译器从触发重载模板调用到确定最优可行候选的完整执行流程,同时针对流程中的疑点提出问题,具体内容如下:
第一个示例 #1
template <class T> void f(const T&); // F1: reference to const T template <class T> void f(const T*); // F2: pointer to const T f((int*)0); // matching F1: // deduction: P = const T&, A = int* --> const T& = int* --> T = int* // instantiates: void f(int *const&); A = int*, P = int *const& // S1 conversion: int* --> int* const& (identity conversion?) // matching F2: // P = const T*, A = int* --> const T* = int*; T = int; // instantaies: void f(const int*); A = int*, P = const int*; // S2 conversion: int* --> const int* (qualification conversion)
根据标准条款[over.ics.rank]/3/3.2规定:标准转换序列S1优于标准转换序列S2的情形包括:S1是S2的真子序列(比较12.2.4.2.2定义的规范形式转换序列,排除左值转换;恒等转换序列被视为任意非恒等转换序列的子序列)。
在本示例中,S1是S2的真子序列:恒等转换是限定转换的真子序列,符合上述条款要求。再根据标准条款[over.match.best.general]/2的规定:若可行函数F1的所有实参对应的隐式转换序列ICSi(F1)均不劣于F2对应的ICSi(F2),且存在至少一个实参j对应的ICSj(F1)优于ICSj(F2),则F1是优于F2的可行函数。
本示例中F1对应的隐式转换为恒等转换,所有实参的转换序列均不劣于F2对应的限定转换,且存在更优的转换序列,因此F1的特化会被重载决议选中。
我的疑问
- 我对上述完整流程的推导是否正确?
- 既然已经通过隐式转换序列比对判定F1为最优可行候选,编译器此时是否还需要执行partial ordering(偏序)流程?如果需要,原因是什么?
第二个示例 #2
template <class T> void f(const T&); // F1: reference to const T template <class T> void f(T*); // F2: pointer to T f((int*)0); // matching F1: // deduction: P = const T&, A = int* --> const T& = int* --> T = int* // instantiates: void f(int *const&); A = int*, P = int *const& // S1 conversion: int* --> int* const& (identity conversion) // matching F2: // deduction: P = T*, A = int* --> T* = int*; T = int // instantaies: void f(int*); A = int*, P = int* // S2 conversion: int* --> int* (identity conversion)
本示例中[over.ics.rank]/3/3.2的规则无法适用,因为S1和S2均为恒等转换,转换序列优先级相同。此时编译器会继续校验[over.match.best.general]/2下的其他规则:虽然F1的ICSi均不劣于F2,但不存在某一实参的转换序列更优,因此无法通过2.1款判定最优候选,会继续向下匹配直到触发[over.match.best.general]/2.5规则:若F1和F2均为函数模板特化,且根据偏序规则F1对应的模板比F2对应的模板更特化,则F1为更优函数。
我对偏序流程的推导总结如下:
调整后的函数签名:
void f(T); // Tem1 void f(T*); // Tem2
转换后的函数签名:
void f(U1); // Tra1 void f(U2*); // Tra2
将Tem1与Tra2匹配:
void f(T); // Tem1 void f(U2*); // Tra2 // T = U2* - OK: T can be deduced from U2*
将Tem2与Tra1匹配:
void f(T*); // Tem2 void f(U1); // Tra1 // T* = U1 - error: T cannot be deduced
根据上述推导,Tra2对应的模板比Tra1对应的模板更特化,即F2比F1更特化,因此F2的特化会被重载决议选中。
我的疑问
- 我对上述完整流程的推导是否正确?
- 我的理解(可能有误)是:完成模板实参推导后,编译器会为两个重载生成特化,用于形参/实参匹配的隐式转换序列比对流程;那么在后续判定出更特化的模板后,编译器是否需要再次为该更特化模板生成特化?
我在提问前已检索大量相关资料,未找到覆盖上述完整流程的解答,希望能确认我的推导思路是否正确,以及我引用的标准条款是否适用于对应示例,占用大家时间非常感谢。
内容的提问来源于stack exchange,提问作者mada

