函数模板实参推导与替换阶段,类模板特化是否会被隐式实例化?
函数模板调用中类模板特化的隐式实例化时机
问题核心
调用模板函数时,在实参推导、替换阶段(早于重载解析),作为函数参数的类模板特化会不会被隐式实例化?结合下方示例代码,以someFunc(boo<foo<int>>());的调用场景为例,分析三个阶段的行为:
示例代码
template<typename T> struct foo{ using foo_type = int; }; template<typename T> struct boo { using boo_type = typename T::foo_type; }; template <typename T> void someFunc(boo<T>) {} template <typename T> typename T::boo_type someFunc(T) {}
1. 实参推导阶段:不会触发实例化
实参推导本质是类型模式匹配,不需要类模板特化的完整定义:
- 对第一个重载
someFunc(boo<T>),只需把实参类型boo<foo<int>>和模板参数boo<T>做形式匹配,推导出T=foo<int>,全程不需要知道boo<foo<int>>的内部结构。 - 对第二个重载
someFunc(T),直接推导出T=boo<foo<int>>,同样只做类型匹配,不涉及类的实例化。
2. 实参替换阶段:仅第二个重载触发实例化
替换阶段是把推导得到的模板参数代入函数模板的各个部分,此时:
- 第二个重载的返回类型是
typename T::boo_type,替换T=boo<foo<int>>后,需要访问boo<foo<int>>::boo_type,这要求boo<foo<int>>的完整定义,因此会触发隐式实例化。 - 第一个重载的参数替换后是
boo<foo<int>>,但函数声明中的类类型参数仅需类的“存在性”(即声明),不需要完整定义,所以此阶段不会实例化boo<foo<int>>。
3. 重载解析完成后:按需触发实例化
重载解析选定候选函数后,只有当程序需要用到类模板特化的完整定义时,才会触发实例化:
- 如果选中第一个重载,若函数体里没有访问
boo<T>的任何成员(示例中第一个重载无函数体),则永远不会实例化boo<foo<int>>;只有当函数体内需要使用boo<T>的成员时,才会触发实例化。 - 如果选中第二个重载,替换阶段已经完成了实例化,此阶段不会重复触发。
内容的提问来源于stack exchange,提问作者HeartBleed
相关产品推荐
相关产品推荐

