模板偏序、auto与引用NTTP:主流编译器的行为差异
C++模板重载解析的编译器行为合规性分析
场景1:模板参数为int&的情况
测试代码:
template <int&> struct X{}; template <int& V> int func(X<V>) { return 0; } template <auto V> int func(X<V>) { return 1; } int i; int main() { return func(X<i>{}); }
标准依据与合规性判断
- 重载可行性分析
根据C++标准条款:
- [temp.param] p4:非类型模板参数允许使用引用类型;
- [temp.arg.nontype] p2:带占位符类型(
auto)的非类型模板参数,可通过模板实参推导得到合法类型,此处auto V会推导为int&类型,符合非类型模板参数的要求。
因此两个函数重载均为可行重载。
- 部分排序与歧义判断
根据[temp.func.order]和[temp.deduct.partial]的部分排序规则:
- 用第一个模板的合成实参(
X<(int&)synth_var>)推导第二个模板的参数,可成功将auto V推导为int&; - 用第二个模板的合成实参(
X<synth_ref>,其中synth_ref为合成的int&类型非类型参数)推导第一个模板的参数,也可成功匹配int& V。
两个模板的特化程度完全相同,因此函数调用存在歧义。
结论:MSVC判定调用存在歧义的行为符合标准;GCC错误地认为第一个模板更特化,Clang错误地判定第二个重载不可行,二者行为不符合标准。
场景2:模板参数为int的情况
修改后的测试代码:
template <int> struct X{}; template <int V> int func(X<V>) { return 0; } template <auto V> int func(X<V>) { return 1; } int main() { return func(X<42>{}); }
标准依据与合规性判断
重载可行性分析
第二个模板的auto V会推导为int类型,符合非类型模板参数要求,两个重载均可行。部分排序与歧义判断
与场景1逻辑一致:两个模板的合成实参均可互相推导成功,特化程度相同,调用存在歧义。
结论:MSVC和Clang判定调用存在歧义的行为符合标准;GCC错误地选择第一个重载,行为不符合标准。
内容的提问来源于stack exchange,提问作者n.m.is-an-unemployed-ai-agent
相关产品推荐
相关产品推荐

