模板参数包如何具有其他尾随参数?

How can a template parameter pack have other trailing arguments?

在C++14标准草案中,[temp.param]/11说:

If a template-parameter of a primary class template or alias template is a template parameter pack, it shall be the last template-parameter.

如果您尝试编译以下模板,编译器会报错。

template< typename ...Args, void(*f)(Args...) > // ERROR
struct Bar
{};

但是在这种情况下它是如何工作的?

template< typename F, F >
struct Bar;

template< typename ...Args, void(*f)(Args...) > // OK ???
struct Bar< void(*)(Args...), f >
{};

我可以看出它与专业化 class 模板的一部分有关,但是 为什么

该规则明确指出它适用于 主要 class 模板。这是否意味着专业化规则会发生变化?

我试图在标准中搜索此内容,但找不到任何内容。你能不能对此有所启发。

The rule clearly states that it applies to a primary class template. Does this mean that the rules change for specializations?

是的。很简单,因为专业化不是主要的 class 模板。因此,如果措辞旨在适用于 all 模板声明,它会这样说。相反,该规则非常旨在仅适用于主要 class 模板(......和别名模板,无法专门化)。专业化没有这样的限制。

这主要是因为不可能在主模板中的模板参数包之后提供任何模板参数,但在专业化中绝对可以这样做。例如,这是连接两个 tuple 专业化的一种方法:

template <typename T, typename U>
struct tuple_concat;

template <typename... Ts, typename... Us> // <== parameter pack *after* parameter pack
struct tuple_concat<tuple<Ts...>, tuple<Us...>> {
    using type = tuple<Ts..., Us...>;
};

这很好,很管用,很有用。但是能够在主要 class/variable/alias 模板中编写这样的东西没有任何好处 - 因此为简单起见禁止这样做。


与所有 C++ 一样,当然有一个脚注。您本可以提供用于触发替换失败的尾随默认模板参数。但是还有其他方法可以解决这个问题,然后我们很快就会有概念。