c++ - 如何解决这个歧义?

标签 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...> {};

那么如何解决这种歧义呢?

最佳答案

问题本质上是没有一个专业比另一个更专业。

在决定选择哪个偏特化时,首先将特化与参数进行匹配,以检查它们是否可行(这里,两者都是)。如果多个是可行的,那么为了决定选择哪一个,我们必须检查哪一个比所有其他的更专业。此过程称为“部分排序”,通过比较彼此专用的模板“参数”(即 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

对于参数模板的每个参数,为每个模板参数组成一些唯一值并代入参数。然后将这些转换后的参数传递给参数模板,以检查推导是否成功。例如:

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

现在让我们看看关键的推论:

  • B2 是根据 A2 推导出来的,但是因为我们对 Start 都使用了唯一值和 N , Start in template A推导不一致,即此处推导失败。

  • 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 .

关于c++ - 如何解决这个歧义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27988605/

相关文章:

c++ - 在堆和栈中创建对象的区别

c++ - 为什么 std::vector 可以比原生数组更高效?

c++ - 在纯 C++ (C++11) 中扩充一个类/应用一个方面

c++ - 动态分配的数组超出范围错误

c++ - QT函数模板

c++ - 推导成员函数和变量的模板参数

c++ - 可变参数推导指南不是由 g++ 采用,由 clang++ 采用 - 谁是正确的?

c++ - 这个编译器错误是什么意思 - C++ 中的 "qualified-id in declaration before ‘=’ token ?

c++ - 如何将尾随返回类型与模板化类成员一起使用

c++ - OpenGL 无缘无故地裁剪一个对象