#include <iostream>
template<typename T>
void test(T,typename T::type){ //#1
}
template<typename T,typename U>
void test(T,U){ //#2
}
int main(){
test(0,0); //we know #2 is called
}
考虑上面的代码,要调用函数test
的参数0,0
,编译器需要为这些参数找到最佳匹配重载并实例化函数模板,首先有两个名为test
的函数模板,编译器从它们的参数中推导出模板参数。我想知道下一步中首先在函数模板上执行的实例化或替换?重载解析是否在它们之后执行?
何时实例化函数模板
如果调用重载函数模板的名称,编译器将尝试推断其模板参数并检查其显式声明的模板参数。如果成功,它将实例化函数模板专用化,然后将此专用化添加到重载解析中使用的候选函数集中
何时执行替换
具体而言,在为重载解析创建候选集时,该集的某些(或全部(候选集可能是实例化模板的结果,其中(可能推导的(模板参数替换为相应的模板参数。如果在替换任何给定模板的一组参数期间发生错误,编译器将从候选集中删除潜在的重载,而不是因编译错误而停止,前提是替换错误是C++标准允许这种处理的错误之一
我没有找到有关替换和实例化顺序的文档
更新:deduction
,substitution
(sfinae 发生在这里(是实例化的一部分,但是,除了这些之外,通过在实例化点替换模板参数来生成定义也是实例化的一部分,什么时候发生?在重载解决之后或substitution
之后(这里是 sfinae(?
您的示例对您的问题没有太多说明,因为只有一个可行的候选者:替换#1
失败,因为int::type
格式不正确,因此只有一个函数,#2
。
另一方面,它确实意味着参数替换必须作为实例化的一部分发生(如@IgorTandetnik所述(。而且,要解决任何重载问题,必须在之前进行模板实例化。
如果将#1
更改为
template <typename T>
void test(T,T){}
您将有两个可行的重载,并且#1
将被选中。
编辑:
另一方面,如果您将主要功能更改为
struct {
using type = int;
int val = 0;
} x;
test(x,0);
两个模板都将实例化,但重载解析将失败,因为两个函数void test(anonymous struct, int)
不明确。
这也说明了必须先实例化模板,然后才能进行重载解析。