函数和继承中的非类型模板参数

Non-type template parameters in function and in inheritance

我正在学习 this 很棒的教程。作者大量使用可变参数模板,我陷入了困境,无法理解。你能帮帮我吗?

1.为什么不编译?

// this is simple
template<size_t I, typename T>
struct tuple_element
{
    T value;
};

// this does NOT compiles: error: parameter pack 'Indices' must be at the end of the template parameter list
template <size_t... Indices, typename... Types>
struct tuple_impl : tuple_element<Indices, Types>...
{
};

接下来,作者有这段编译好的代码:

template <size_t... Indices>
struct index_sequence
{
    using type = index_sequence<Indices...>;
};

template <typename Sequence, typename... Types>
struct tuple_impl;

template <size_t... Indices, typename... Types>
struct tuple_impl<index_sequence<Indices...>, Types...>
  : tuple_element<Indices, Types>...
{
};

2。为什么在这种情况下一切正常? 我在这里看到几乎相同的模式:tuple_element<Indices, Types>...

3。为什么不能编译:

template <size_t... Indices>
void g(Indices...){}; //error: variable or field 'g' declared void 

您看到的错误是在参数传递中。这是一个编译错误:

template <size_t... Indices, typename... Types>
struct tuple_impl
{};

live example

规则是模板中不能有一个包后跟另一个包 class 模板参数列表。

第二个例子是一个专业化,其中包规则不存在。特化的模板参数仅仅是从针对主模板的模式匹配中提取的类型和值,按照类型名称后特化的 <> 部分的指导。

因为它们永远不会以相同的列表和顺序传入,所以一个 ... 一个接一个地出现不会造成任何歧义。对于主模板,顺序很重要,... 之后的任何内容都很难与 ... 的更多内容区分开来。可能是为了让编译器的工作更轻松,即使在它不能模棱两可的情况下(比如,一组文字后跟一组类型),C++ 禁止使用它。

  1. 编译器无法区分第一个序列何时结束和第二个序列何时开始 - 因此在可变参数模板中允许只有一个参数包,在最后。

    tuple_impl<a, b, c, d, e, f> //is d still an index or already a type? what about e?
    
  2. 这是可行的,因为 tuple_impl 本身是一个模板,它本身只有一个参数包,即 Types...。碰巧在这个专业化中,第一个参数也是一个模板,它也有一个参数包。因此,与一个模板有两个包相比,您有两个模板各有一个包,这没问题。

  3. 这与可变参数模板无关,即出于同样的原因,它也不适用于单个参数。事实是,由于 Indices... 不是类型而是值,因此您没有定义函数。如果它不是 void,编译器稍后就会有问题。考虑这个例子,它略有修改但本质上是一个类似的结构:

    template <size_t I>
    unsigned g(I)
    {}
    

中间一行居中:编译器认为是变量定义,用I初始化。因此,您的情况会出现错误,因为 void 类型的变量根本没有意义。然后我的编译器发出关于模板的警告,它认为 g 是一个模板变量,而那些是 C++1y 扩展。完成后,他意识到 ; 未完成变量定义,发出错误并退出...

只是补充一些重要的事情:这是一个测试片段:

int main( int argc, char** argv )
{
    using i3 = index_sequence<1, 2, 3>;
    tuple_impl<i3, int, double, char> tup;

    return 0;
}

注意:此处您将此 i3 作为 "index pack" 传递。 "master template" 始终定义必须如何将参数传递给模板。 template<...> 语句 if set for specialization 没有定义任何东西,只是参数组合在内部可能在专业化内部传播,但它不是 public 接口的一部分。

例如,如果您尝试使用 <1, 2, 3, int, double, char> 作为参数规范(理论上与专业化的模板参数规范匹配),它将无法编译。