如何解决这种歧义?

时间:2015-01-16 16:39:29

标签: c++ templates c++11

在以下代码中:

template <int...> struct IndexSequence {};

template <int, int, typename, int...> struct Helper;

template <int Start, typename Coefficients, int... Is>
struct Helper<Start, Start, Coefficients, Is...> {
    using type = IndexSequence<Is...>;
};

template <int Start, int N, int... As, int... Is>
struct Helper<Start, N, IndexSequence<As...>, Is...> :
    Helper<Start, N-1, IndexSequence<As...>, N-1, Is...> {};

int main() {
    Helper<2,5, IndexSequence<1,2,3>>::type a;
}

我收到编译错误:

ambiguous class template instantiation for 'struct Helper<2, 2, IndexSequence<1, 2, 3>, 2, 3, 4>'

我认为它会解决专业化问题

template <int Start, typename Coefficients, int... Is>
struct Helper<Start, Start, Coefficients, Is...> {
    using type = IndexSequence<Is...>;
};

但我想它也在阅读

struct Helper<Start, N, IndexSequence<As...>, Is...> :
    Helper<Start, N-1, IndexSequence<As...>, N-1, Is...> {};

那么如何解决这种歧义?

1 个答案:

答案 0 :(得分:3)

问题基本上是没有专业化比其他专业化更专业化。

在决定选择哪个部分特化时,首先将特化与参数匹配,以检查它们是否可行(这里两者都是)。如果多个是可行的,那么要决定选择哪一个,我们必须检查哪一个比其他所有更专业。这个过程被称为&#34;部分排序&#34;并通过比较专门模板&#34;参数&#34;彼此(即Helper<...>中的模板参数) - 一个模板作为参数模板,另一个模板作为参数模板。参数模板提供类型,并且执行演绎以查看是否可以在给定参数模板的类型的情况下推导出参数模板中的模板参数。

template <int Start, typename Coefficients, int... Is>
struct Helper<Start, Start, Coefficients, Is...>
//            ^^^^^  ^^^^^  ^^^^^^^^^^^^  ^^^^^
//   A:         1      2         3          4

template <int Start, int N, int... As, int... Is>
struct Helper<Start, N, IndexSequence<As...>, Is...>
//            ^^^^^  ^  ^^^^^^^^^^^^^^^^^^^^  ^^^^^
//   B:         1    2            3             4

对于参数模板的每个参数,为每个模板参数组成一些唯一值并替换为参数。然后将这些转换后的参数传递给参数模板,以检查推导是成功还是失败。举个例子:

  • A1推断B1成功。 (int可以从int
  • 推断出来
  • 如上所述,B1是针对A1,......推断的。工作正常。

现在让我们来看看关键的扣除:

  • B2是针对A2推断的,但由于我们对StartN使用了唯一值,因此模板A中的Start推断不一致 ,这意味着扣除失败。

  • A3是针对B3推断的,但由于Coefficients是一些独特的类型(不是IndexSequence的特化!),因此扣除失败。

两个方向上,扣除至少失败一次:因此,没有一个模板完全比另一个更专业。


通过例如解决这种部分排序歧义写第一个专业作为

template <int Start, int... As, int... Is>
struct Helper<Start, Start, IndexSequence<As...>, Is...> {
    using type = IndexSequence<Is...>;
};

现在,上面失败的第二次扣除不再失败。只有将专业化B作为参数模板的那个。这意味着B更专业,因此被选中。

Demo