C++模板偏特化歧义疑问:GCC编译报错原因解析
C++模板偏特化的歧义问题解析
// 主模板 template<class T, class U1, class U2, class... Us> struct S{}; // #1 template<class T, class... Us> struct S<T, T, T, Us...>{}; // #2 template<class T, class U, class... Us> struct S<T, T, U, Us...>{}; // #3 template<class T, class U, class... Us> struct S<T, U, T, Us...>{}; // #4 template<class T, class U1, class U2, class U3, class... Us> struct S<T, U1, U2, U3, Us...>{};
当实例化S<int, int, long, float, double>时,GCC会报错提示无法在#2和#4的特化版本中选择。直观上可能认为#2更特化,但这是对模板偏特化排序规则的误解,具体分析如下:
按照cppreference的模板偏特化排序规则,我们将两个特化转化为虚构函数模板,通过互相推导判断特化程度:
- 对应#2的虚构函数模板#A:
template<class T, class U, class... Us> void f(S<T, T, U, Us...>); // #A - 对应#4的虚构函数模板#B:
template<class T, class U1, class U2, class U3, class... Us> void f(S<T, U1, U2, U3, Us...>); // #B
判断特化程度的核心是:能否证明其中一个模板的所有匹配实例,都能被另一个模板匹配:
- 检查#2的实例是否都能被#4匹配:
取#2的实例S<int, int, long>(Us...为空),该实例仅3个模板参数,但#4要求至少4个参数(T、U1、U2、U3),无法匹配#4。这说明存在#2能匹配但#4不能匹配的实例,#2不被#4包含。 - 检查#4的实例是否都能被#2匹配:
取#4的实例S<int, long, float, double>,该实例前两个参数为int和long,不满足#2要求的前两个参数必须相同的约束,无法匹配#2。这说明存在#4能匹配但#2不能匹配的实例,#4也不被#2包含。
结论:#2和#4是交叉覆盖的关系,互相都有对方无法匹配的实例,因此编译器无法判定哪个更特化,最终触发歧义报错。
内容的提问来源于stack exchange,提问作者ElevenLee
相关产品推荐
相关产品推荐

