我正在尝试完成一个模板元编程练习text。然而,当我试图部分专门化一个非类型模板参数时,我遇到了不同的行为。
我定义了一个编译时向量。
template <int... Nums>
struct Vector {};
然后,我定义了一个关于“Vector”的“Get”操作,代码可以编译。
template <size_t Idx, typename Vec>
struct Get;
template <int Head, int... Tail>
struct Get<0, Vector<Head, Tail...>> // partial specialize the "Idx"
{
static constexpr int value = Head;
};
template <size_t Idx, int Head, int... Tail>
struct Get<Idx, Vector<Head, Tail...>>
{
static_assert(Idx > 0, "Out of Vector bound");
static constexpr int value = Get<Idx - 1, Vector<Tail...>>::value;
};
但是,当我尝试像下面这样定义“插入”操作时,VS2022中的代码编译失败,错误代码为“C2752多个部分专门化匹配”。
template <size_t Pos, int Val, typename Vec>
struct Insert;
template <size_t Pos, int Val, typename Vec>
using InsertT = typename Insert<Pos, Val, Vec>::type;
template <int Val, int... Elems>
struct Insert<0, Val, Vector<Elems...>> // partial specialize the "Pos"
{
using type = Vector<Val, Elems...>;
};
template <size_t Pos, int Val, int Head, int... Tail>
struct Insert<Pos, Val, Vector<Head, Tail...>>
{
using type = PrependT<Head, InsertT<Pos - 1, Val, Vector<Tail...>>>; // push an element in the front of the vector
};
最新消息:
#include <type_traits>
template <int... Nums>
struct Vector {};
template <int, typename>
struct Prepend;
template <int Ele, typename Vec>
using PrependT = typename Prepend<Ele, Vec>::type;
template <int Ele, int... Nums>
struct Prepend<Ele, Vector<Nums...>>
{
using type = Vector<Ele, Nums...>;
};
template <size_t Idx, typename Vec>
struct Get;
template <int Head, int... Tail>
struct Get<0, Vector<Head, Tail...>> // partial specialize the "Idx"
{
static constexpr int value = Head;
};
template <size_t Idx, int Head, int... Tail>
struct Get<Idx, Vector<Head, Tail...>>
{
static_assert(Idx > 0, "Out of Vector bound");
static constexpr int value = Get<Idx - 1, Vector<Tail...>>::value;
};
template <size_t Pos, int Val, typename Vec>
struct Insert;
template <size_t Pos, int Val, typename Vec>
using InsertT = typename Insert<Pos, Val, Vec>::type;
template <int Val, int... Elems>
struct Insert<0, Val, Vector<Elems...>> // partial specialize the "Pos"
{
using type = Vector<Val, Elems...>;
};
template <size_t Pos, int Val, int Head, int... Tail>
struct Insert<Pos, Val, Vector<Head, Tail...>>
{
using type = PrependT<Head, InsertT<Pos - 1, Val, Vector<Tail...>>>; // push an element in the front of the vector
};
int main()
{
// test Vector
static_assert(std::is_same_v<Vector<1, 2>, Vector<1, 2>>);
// test Prepend
static_assert(std::is_same_v<Prepend<1, Vector<2, 3>>::type, Vector<1, 2, 3>>);
// test Get
static_assert(Get<0, Vector<0, 1, 2>>::value == 0);
static_assert(Get<1, Vector<0, 1, 2>>::value == 1);
static_assert(Get<2, Vector<0, 1, 2>>::value == 2);
// test Insert
static_assert(std::is_same_v<Insert<0, 3, Vector<4, 5, 6>>::type, Vector<3, 4, 5, 6>>);
static_assert(std::is_same_v<Insert<1, 3, Vector<4, 5, 6>>::type, Vector<4, 3, 5, 6>>);
static_assert(std::is_same_v<Insert<2, 3, Vector<4, 5, 6>>::type, Vector<4, 5, 3, 6>>);
static_assert(std::is_same_v<Insert<3, 3, Vector<4, 5, 6>>::type, Vector<4, 5, 6, 3>>);
}
在我看来,两种操作中的部分专门化是相同的。为什么一个编译成功,而另一个编译失败?
1条答案
按热度按时间mpbci0fu1#
正如@Igor Tandetnik所提到的,原始代码不起作用的原因是
Insert<0, Val, Vector<Elems...>>
在第一个参数上比Insert<Pos, Val, Vector<Head, Tail...>>
更专业,但Vector<Elems...>
比Vector<Head, Tail...>
更不专业。**因此,没有一个专业化比另一个专业化更专业化。基于上述事实,Igor Tandetnik提出了以下解决方案。这个解决方案主要有两个修改,一方面,将
Vector<Elems...>
改为Vector<Head, Tail...>
,这样Insert<0, Val, Vector<Elems...>>
和Insert<Pos, Val, Vector<Head, Tail...>>
在Pos
中只会有差异。另一方面,增加了一个专门化,以处理在Pos=0
处将Val
添加到空Vector
的情况。@Bob__给出了另一个基于C++20的
requires
的解决方案。requires
描述了对Pos
参数的约束。