可变参数模板样板参数可以部分专业化吗? [英] Can variadic template template parameter be partial-specialized?

查看:80
本文介绍了可变参数模板样板参数可以部分专业化吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下程序:

template<template<typename ...> class>
struct foo {};

template<template<typename> class C>
struct foo<C> {};

int main() {}

Clang拒绝并显示错误:

Clang rejects it with error:

类模板部分专业化不对任何模板参数进行专业化

class template partial specialization does not specialize any template argument

即使在最新的lang 7.0 HEAD中,也请参见演示此处.但是, gcc接受.

even in latest clang 7.0 HEAD, see demo here. However, gcc accepts it.

请参阅 [temp.class.spec] ,其中陈述了部分专业化的规则,我找不到任何禁止此模板部分专业化的东西.特别是,专业化确实是更专业化,错误消息看起来不正确.

Refer to [temp.class.spec] where the rules of partial specialization are stated, I couldn't find anything that prohibits the partial specialization of this template. Especially, the specialization is indeed more specialized, the error message looks incorrect.

但是,gcc的行为也异常,请考虑以下程序:

However, gcc's behavior is also abnormal, consider the following program:

#include <iostream>

template<template<typename ...> class>
struct foo { void show() { std::cout << "Primary.\n"; } };

template<template<typename> class C>
struct foo<C> { void show() { std::cout << "Specialized.\n"; } };

template<class...> struct bar {};

int main() {
    foo<bar> f;
    f.show();
}

事实证明,在这种情况下,gcc使用了专用版本,请参见此处.

It turns out that gcc uses the specialized version in this case, see here.

现在我想问:

  • 标准允许这种局部专业化吗?

  • is this kind of partial specialization allowed by standard ?

哪个编译器正确? (一个/全部/没有?)

which compiler is correct ? ( one/all/none of them ? )

推荐答案

在实现新的C ++模板模板参数推论

This finaly seems to be a GCC bug in the implementation of the new C++ template template argument deduction partial support for this feature.

要确定部分专业化是否比类模板更专业,请部分排序适用于2个相应的综合功能:

To determine if a partial specialization is more specialized than the class template, partial ordering is applied to 2 corresponding synthetized functions:

//template class:
template<template<class...>class P> void f_foo0(foo<P>);

//Partial specialization
template<template<class P> class P> void f_foo_partial0(foo<P>);

然后尝试通过使用与另一个函数参数相对应的参数调用每个函数来执行模板参数推导(请参见

Then it is attempted to perform template argument deduction, by calling each functions with an argument corresponding to the other function parameter (see [temp.func.order])

template<class P> struct Atype{};
template<class ...P> struct ATypePack{};

//Is f_foo_partial at least as specialized as f_foo?
f_foo(foo<AType>{});

//Is f_foo at least as specialized as f_foo_partial?
f_foo_partial(foo<ATypePack>{});

如果(1)的模板参数成功,则f_foo_partial至少与f_foo一样专门化.如果(2)的模板参数成功,则f_foo至少与f_foo_partial一样专门.(请参阅

If template argument succeed for (1) then f_foo_partial is at least as specialized as f_foo. If template argument succeed for (2) then f_foo is at least as specialized as f_foo_partial.( see [temp.deduct.partial]). Then if only one is at least as specialized as the other, then it is the one which is more specialized.

因此检查模板参数是否可扣除,然后执行从类型中推导模板参数

然后要执行此匹配,将应用C ++ 17中引入的规则 [temp.arg.template]/3 :

Then to perform this matching, the introduced rule in C++17 is applied [temp.arg.template]/3:

当P至少与模板参数A一样专门化时,模板参数与模板模板参数P匹配.[...]

A template-argument matches a template template-parameter P when P is at least as specialized as the template-argument A.[...]

和[temp.arg.template]/4指定将使用以下两个发明的函数,与前面的情况类似地执行此排序:

And [temp.arg.template]/4 specify that this ordering will be performed similarily to the preceding case using these invented two functions:

template<class...> struct X{};
//for the argument
template<class...P> void f_targ(X<P...>);

//Partial specialization
template<class P> void f_tparam(X<P>);

struct Atype{};
struct ATypePack{};

//Is template template parameter at least as specialized template template arg?
f_targ(X<AType>{});

//Is template template arg at least as specialized as template template parameter?
f_tparam(X<ATypePack>{});

    (1)模板参数的
  • 继承了...P`` is AType`的推导参数.

    • for (1) template argument succeed the deduced argument for ...P`` isAType`.

      对于(2),有一条特殊规则,仅适用于模板局部排序[temp.deduct.type]/9.2的情况:

      for (2) there is a special rule, that applies only in the case of template partial ordering [temp.deduct.type]/9.2:

      [...] 在部分订购期间,如果Ai最初是背包扩展:

      • 如果P不包含与Ai对应的模板参数,则Ai 被忽略;

      • if P does not contain a template argument corresponding to Ai then Ai is ignored;

      否则,如果Pi不是包扩展,则模板参数推导将失败.

      template<class P> void p_foo_partial(foo<P>)的函数参数中,Ai是ATypePackPiP.

      Here Ai is ATypePack and Pi is the P in the function argument of template<class P> void p_foo_partial(foo<P>).

      因此,由于用粗体标出了此规则,所以(2)的模板参数推导失败,因此模板模板参数"class P"比其参数更专业.因此,呼叫f_foo_partial(foo<ATypePack>{})的格式正确.

      So due to this rule cited in bold, template argument deduction fails for (2), so template template parameter "class P" is more specialized than its argument. So the call f_foo_partial(foo<ATypePack>{}) is well formed.

      另一方面,由于[temp.arg.temp]/3,对f_foo(AType{})的调用格式正确:

      On the other hand the same rules, the call to f_foo(AType{}) is well formed because of [temp.arg.temp]/3:

      [...]如果P包含参数包,则如果A的每个模板参数与P的template-parameter-list中的相应模板参数匹配,则A也与P匹配.[...]

      [...] If P contains a parameter pack, then A also matches P if each of A's template parameters matches the corresponding template parameter in the template-parameter-list of P.[...]

      因此,f_foo_partial的专业程度不及f_foo,因此template<class<class > class C> struct foo<C>;并非模板foo的部分专业化.

      so f_foo_partial is not more specialized than f_foo, so template<class<class > class C> struct foo<C>; is not a partial specialization of template foo.

      这篇关于可变参数模板样板参数可以部分专业化吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆