非类型模板参数占位符与函数重载决议问题及C++17场景问询
关于非类型模板参数占位符与函数重载决议的问题解答
第一个问题:非类型模板参数的占位符类型是否会触发函数重载决议?
答案是肯定的。当你把重载函数名作为实参传递给带占位符类型(比如auto)的非类型模板参数时,编译器必须先通过重载决议确定到底用哪个重载版本,才能完成模板参数的类型推导和模板实例化。
说白了,占位符类型的非类型模板参数会给编译器一个“匹配模板”的目标轮廓(比如你的例子里是「接受int参数的函数指针」),编译器会拿着这个轮廓去筛选候选的重载函数,找到唯一符合的那个。
后续问题:C++17是否允许在不掌握隐式转换返回类型的前提下,对传递给模板的函数名执行重载决议?
C++17完全允许这种场景,而且你的示例代码就是典型的合法情况,这也是GCC和Clang都接受它的原因。
咱们结合你的代码来分析:
template <auto(*)(int)> struct Foo { }; int bar(int); float bar(float); int main() { static_cast<void>(Foo<bar>{}); }
- 模板
Foo的非类型参数是一个函数指针,它的签名是「接受int参数,返回类型由auto推导」。 - 当你传递
bar时,编译器会遍历bar的所有重载:float bar(float)的参数是float,和模板要求的int参数不匹配,直接被排除;- 只剩下
int bar(int),它的参数类型完全匹配模板的要求,因此编译器会把auto推导为int,最终模板参数的类型确定为int(*)(int)。
- 这个过程里不需要依赖任何隐式转换——因为我们直接匹配到了参数类型完全一致的重载,返回类型是通过选中的重载直接推导出来的,不存在“不知道返回类型就无法做重载决议”的问题。
如果出现多个重载都匹配参数类型的情况(比如同时存在int bar(int)和long bar(int)),编译器就会因为歧义而报错,因为它无法确定该选哪个重载来推导auto的类型。
内容的提问来源于stack exchange,提问作者W.F.
相关产品推荐
相关产品推荐

