我试图理解为什么编译器无法使用如下代码进行所有推导:
template <typename tuple_types>
struct TupleX;
template <typename... head_types, typename tail_type>
struct TupleX< std::tuple<head_types..., tail_type> > // Error
{
using Tail = tail_type;
};
using FooX = std::tuple<int, float, double>;
using BarX = typename TupleX<FooX>::Tail;
Visual C++ 2022 无法使用以下命令构建它:
error C2027: use of undefined type 'TupleX<FooX>' see declaration of 'TupleX<FooX>'
error C2061: syntax error: identifier 'Tail'
虽然顺序相反,但推导仍按预期进行:
template <typename tuple_types>
struct TupleX;
template <typename head_type, typename... tail_types>
struct TupleX< std::tuple<head_type, tail_types...> >
{
using Head = head_type;
};
using FooX = std::tuple<int, float, double>;
using BarX = typename TupleX<FooX>::Head;
static_assert(std::is_same_v<BarX, std::tuple_element_t<0, FooX> >);
考虑到以上所有内容,我提出了几个问题,希望是正确的。
为什么编译器不能使用这样的模式
因为模板参数会消耗所有传递的模板参数。这会导致
tail_type
在示例的第一种情况下为空。但由于tail_type
是非参数包,所以不能留空。
我提出的实现中是否存在一些逻辑错误?
问题在于你的逻辑的实现。
特别是,在第一种情况下
head_type
是一个参数包,这意味着它消耗所有传递的参数参数(此处为FooX
)。这反过来意味着 tail_type
将为空,但这是不允许的,因为 tail_type
是 不是参数包,因此 不能留空。
因此,在这种情况下,专业化不是匹配,唯一的匹配是将要使用的主要模板。但由于您只有主模板的声明,因此我们收到了提到的不完整错误。
第二种情况有效,因为现在
tail_type
是一个参数包并且可以留空。在这种情况下传递的 FooX
将与 head_type
匹配。