为何函数参数带默认值时仍需默认模板参数?结合编译差异场景求解
咱们先来看这段有意思的代码:同样是带默认参数的模板睡眠函数,sleep()编译报错,但sleep2()却能正常通过,这到底是咋回事呢?
#include <iostream> #include <chrono> using namespace std; template<typename Dur> void sleep( Dur dur = std::chrono::milliseconds::min() ) { } template<typename Dur = std::chrono::milliseconds> void sleep2( Dur dur = Dur::min() ) { } int main() { sleep(); // 编译失败 sleep2(); // 编译成功 }
核心原因:模板参数推导与默认参数的执行顺序
编译器处理模板函数调用的逻辑是先确定模板参数类型,再处理函数的默认参数,咱们分别拆解两个函数的编译过程:
对于
sleep():
当你调用空参数的sleep()时,编译器首先需要推导模板参数Dur的类型,但你既没有显式指定Dur,也没有传递函数实参——虽然函数参数有默认值,但这个默认值std::chrono::milliseconds::min()的类型是std::chrono::milliseconds,可编译器没办法提前用这个默认值来推导Dur,因为默认参数的生效是在模板参数确定之后的步骤。这就导致编译器陷入了“不知道Dur就没法解析默认参数,没参数又没法推导Dur”的死循环,最终抛出推导失败的错误(比如MSVC会提示无法推导模板参数Dur,clang++也会给出类似的推导失败信息)。对于
sleep2():
这个模板函数给Dur设置了默认模板参数std::chrono::milliseconds,当你调用空参数的sleep2()时,编译器直接使用这个默认的模板参数类型,接下来再处理函数的默认参数Dur::min(),此时Dur已经确定是std::chrono::milliseconds,所以Dur::min()就能正常解析为该类型的最小值,顺利生成具体的函数实例,自然编译通过。
简单来说:函数的默认参数没法帮编译器推导模板参数,只有显式指定模板参数默认值,才能在空调用时让编译器确定模板类型,进而解析函数的默认参数。
备注:内容来源于stack exchange,提问作者Edison von Myosotis

