提问人:ssmaniot 提问时间:5/16/2023 更新时间:5/16/2023 访问量:86
由于非类型参数专用化而导致的模棱两可的模板实例化
Ambiguous Template Instantiation due to Non-Type Parameter Specialization
问:
我正在尝试使用 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<Em, Idx, TList> 操作,以在 TList 列表的 Idx 位置插入一个新元素 Em。在我的实现中,我提供了一个模板部分专用化,以便结构中提供的类型与 相同。但是,它被认为与其他部分专业化模棱两可。我不明白为什么,因为第一个部分专业化应该是模式限制性的,以及如何解决这个问题。Insert<Em, 0, List<I...>>
Append<Em, TList>
Insert<Em, Idx, List<H, I...>>
答:
2赞
Jarod42
5/16/2023
#1
你错过了一个案例:
template <int Em, int H, int... I>
struct Insert<Em, 0, List<H, I...>> : Append<Em, List<H, I...>> {};
评论
idx == 0