2011-08-08 39 views
10

有人可以解释为什么这些两个专业没有区别的编译器(gcc 4.5.1 @ ideone)模板偏特

http://ideone.com/9tNux

template <typename... T> struct S; 

template<typename A, typename B, typename... C> 
struct S<A, B, C...> { 
    int f() {return 1;} 
}; 

template<typename... A, typename... C> 
struct S< S<A...>, C...> { 
    int f() {return 2;} 
}; 

,当我尝试实例S<S<a, b>, a, b> o2;编译器抱怨:

prog.cpp:20:21: error: ambiguous class template instantiation for 'struct S<S<a, b>, a, b>' 
prog.cpp:6:22: error: candidates are: struct S<A, B, C ...> 
prog.cpp:11:33: error:     struct S<S<A ...>, C ...> 
prog.cpp:20:21: error: aggregate 'S<S<a, b>, a, b> o2' has incomplete type and cannot be defined 

而当最后一个专业化改为:

template<typename... A, typename B, typename... C> 
struct S< S<A...>, B, C...> { 
    int f() {return 2;} 
} 

一切工作正常。

+0

我想你也可以在这篇文章中添加代码,因为它对于这个问题非常重要。 – UncleBens

+0

@UncleBens代码已添加。 – Predrag

回答

9

我对问题的理解:

typedef S<S<a, b>, c, d> S2; 

这里S<a,b>第二专业化匹配较好。但是,c, d与第一个专业化的其余参数(单个arg + list与list)更匹配。因此它是1:1。

如果您在B在第二个特发表评论,那么第二个专业化匹配更好,因为它是更专业化的第一个参数(S<...>),其余都是一样的好。

+0

很好的解释,+1!比我做的混乱好多了。 –

+0

容易理解。谢谢! – Predrag

8

我弄糟了这个;它现在应该可以,但信用是由于下面的@UncleBens得到了正确的结果(并且应该得到“接受”)。


如果没有你的第三个版本的B,你有两个当实例S<S<X,Y,Z>, T1, T2, T3>两者同样特定部分专业:

  • 首先PS:A = S<X,Y,Z>B = T1C... = T2, T3
  • 第二个PS没有BA... = X,Y,Z,C... = T1, T2, T3
  • 第二个PS与BA... = X,Y,Z,B = T1,C... = T2, T3

这不会在部分特化排序中建立可比较的元素!

请注意,您可以说template <typename ...> struct S;template <typename A, typename ...B> struct S<A, B...>;,第二个比第一个更具体,因为它具有更多的非可变参数。

但是另一方面,没有B,当你说S<S<X,Y,Z>,T1,T2,T3>,那么第一个参数在第二个PS中匹配得更好,但其余参数在第一个PS中匹配得更好。但是,使用B,第二个PS更具体。

比较这对部分特说其实更具体:

template <typename ...A, typename B, typename ...C> 
struct S<B, std::tuple<C...>, std::tuple<C...>> { /* ... */ }; 

现在很清楚如何是否给定的实例专业化,或者只是一般的格式匹配。专业化拥有固定数量的参数(3),所以它通过可变数量的参数赢得了另一种专业化。

+0

但我的专业不是',B,C ...>和',C ...>'。它们是''和'< S,C ...>'。 – Predrag

+0

这个答案似乎是错误的,因为在你的开放示例中,第二个专业化看起来比第一个更专业。看起来规则是'A'胜过'A ...':在OP的问题中,第二个特化与第一个参数更好地匹配,但第一个特化更好地匹配第二个参数。因此,为什么它编译如果B评论英寸 – UncleBens

+0

@UncleBens:是的,我注意到...一秒钟,让我编辑它 –