在C ++ 14草案标准中,[temp.param]/11说:
如果是主类模板或别名模板的模板参数 是模板参数包,它应该是最后一个模板参数。
如果您尝试编译以下模板,则编译器将抱怨。
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 >
{};
我可以看到它与专业化类模板的一部分有关,但是为什么?
该规则明确指出它适用于 primary 类模板。这是否意味着规则会因专业而改变?
我尝试在标准中搜索此内容,但找不到任何内容。你能给它照亮些吗?
答案 0 :(得分:3)
该规则明确指出它适用于主类模板。这是否意味着规则会因专业而改变?
是的。完全是因为专业化不是主类模板。因此,如果该措辞旨在适用于 all 模板声明,则应这样说。相反,该规则非常旨在仅适用于主类模板(...和别名模板,它们不能专门化)。专业化没有这种限制。
从根本上讲,这是因为不可能在主模板中的模板参数包之后提供任何模板参数,但是在专门领域中绝对可以这样做。例如,这是一种将两个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...>;
};
这很好,它可以工作,很有用。但是,能够在主类/变量/别名模板中编写这样的内容并没有好处†-因此为简单起见,禁止使用它。
†与C ++一样,当然还有脚注。您可能已经能够提供用于触发替换失败的尾随默认模板参数。但是,还有其他方法可以解决该问题,然后无论如何我们很快就会有Concepts。