由于非类型参数特化导致模板实例化不明确

问题描述 投票:0回答:0

我正在尝试使用 TMP 实现列表及其操作。

以下代码编译不通过,

Insert_t
实例化失败(最后一行):

#include <type_traits>

template <int... I>
struct List;

template <int Em, typename TList>
struct Append;

template <int Em, typename TList>
using Append_t = typename Append<Em, TList>::type;

template <int Em, int... I>
struct Append<Em, List<I...>> {
  using type = List<Em, I...>;
};

template <int Em, int Idx, typename TList>
struct Insert;

template <int Em, int Idx, typename TList>
using Insert_t = typename Insert<Em, Idx, TList>::type;

template <int Em, int... I>
struct Insert<Em, 0, List<I...>> : Append<Em, List<I...>> {};

template <int Em, int Idx, int H, int... I>
struct Insert<Em, Idx, List<H, I...>> : Append<H, Insert_t<Em, Idx-1, List<I...>>> {};

static_assert(std::is_same_v<Insert_t<4, 4, List<0, 1, 2, 3>>, List<0, 1, 2, 3, 4>>);   // OK
static_assert(std::is_same_v<Insert_t<-1, 3, List<6, 3, 1, 4>>, List<6, 3, 1, -1, 4>>); // Fails

g++ 编译器给出以下错误,clang 提供相同的错误。我不明白为什么实例化不明确,因为我提供了索引为 0 的专业化:

main.cpp: In instantiation of ‘struct Insert<-1, 1, List<1, 4> >’:
main.cpp:27:8:   recursively required from ‘struct Insert<-1, 2, List<3, 1, 4> >’
main.cpp:27:8:   required from ‘struct Insert<-1, 3, List<6, 3, 1, 4> >’
main.cpp:21:7:   required by substitution of ‘template<int Em, int Idx, class TList> using Insert_t = typename Insert::type [with int Em = -1; int Idx = 3; TList = List<6, 3, 1, 4>]’
main.cpp:30:61:   required from here
main.cpp:27:8: error: ambiguous template instantiation for ‘struct Insert<-1, 0, List<4> >’
  27 | struct Insert<Em, Idx, List<H, I...>> : Append<H, Insert_t<Em, Idx-1, List<I...>>> {};
     |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:24:8: note: candidates are: ‘template<int Em, int ...I> struct Insert<Em, 0, List<I ...> > [with int Em = -1; int ...I = {4}]’
  24 | struct Insert<Em, 0, List<I...>> : Append<Em, List<I...>> {};
     |        ^~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:27:8: note:                 ‘template<int Em, int Idx, int H, int ...I> struct Insert<Em, Idx, List<H, I ...> > [with int Em = -1; int Idx = 0; int H = 4; int ...I = {}]’
  27 | struct Insert<Em, Idx, List<H, I...>> : Append<H, Insert_t<Em, Idx-1, List<I...>>> {};
     |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:27:8: error: invalid use of incomplete type ‘struct Insert<-1, 0, List<4> >’
main.cpp:18:8: note: declaration of ‘struct Insert<-1, 0, List<4> >’
  18 | struct Insert;
     |        ^~~~~~
main.cpp: In instantiation of ‘struct Insert<-1, 2, List<3, 1, 4> >’:
main.cpp:27:8:   required from ‘struct Insert<-1, 3, List<6, 3, 1, 4> >’
main.cpp:21:7:   required by substitution of ‘template<int Em, int Idx, class TList> using Insert_t = typename Insert::type [with int Em = -1; int Idx = 3; TList = List<6, 3, 1, 4>]’
main.cpp:30:61:   required from here
main.cpp:27:8: error: no type named ‘type’ in ‘struct Insert<-1, 1, List<1, 4> >’
  27 | struct Insert<Em, Idx, List<H, I...>> : Append<H, Insert_t<Em, Idx-1, List<I...>>> {};
     |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp: In instantiation of ‘struct Insert<-1, 3, List<6, 3, 1, 4> >’:
main.cpp:21:7:   required by substitution of ‘template<int Em, int Idx, class TList> using Insert_t = typename Insert::type [with int Em = -1; int Idx = 3; TList = List<6, 3, 1, 4>]’
main.cpp:30:61:   required from here
main.cpp:27:8: error: no type named ‘type’ in ‘struct Insert<-1, 2, List<3, 1, 4> >’
main.cpp: In substitution of ‘template<int Em, int Idx, class TList> using Insert_t = typename Insert::type [with int Em = -1; int Idx = 3; TList = List<6, 3, 1, 4>]’:
main.cpp:30:61:   required from here
main.cpp:21:7: error: no type named ‘type’ in ‘struct Insert<-1, 3, List<6, 3, 1, 4> >’
  21 | using Insert_t = typename Insert<Em, Idx, TList>::type;
     |       ^~~~~~~~
main.cpp:30:20: error: template argument 1 is invalid
  30 | static_assert(std::is_same_v<Insert_t<-1, 3, List<6, 3, 1, 4>>, List<6, 3, 1, -1, 4>>);
     |                    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

我想实现一个 Insert 操作以在列表 TList 中的位置 Idx 插入一个新元素 Em。在我的实现中,我为

Insert<Em, 0, List<I...>>
提供了一个模板部分特化,以便结构中提供的类型与
Append<Em, TList>
相同。但是,它被认为与其他偏特化
Insert<Em, Idx, List<H, I...>>
不明确。我不明白为什么,因为第一个部分专业化应该是模式限制的,以及如何解决这个问题。

c++ list templates template-meta-programming
© www.soinside.com 2019 - 2024. All rights reserved.