问题描述
请考虑以下程序:
template<template<typename ...> class>
struct foo {};
template<template<typename> class C>
struct foo<C> {};
int main() {}
Clang拒绝并显示错误:
Clang rejects it with error:
即使在最新的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
一样专门.(请参阅 [temp.deduct.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:
和[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`` is
AType`.对于(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:
-
如果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是ATypePack
,Pi
是P
.Here Ai is
ATypePack
andPi
is theP
in the function argument oftemplate<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:因此,
f_foo_partial
的专业程度不及f_foo
,因此template<class<class > class C> struct foo<C>;
并非模板foo
的部分专业化.so
f_foo_partial
is not more specialized thanf_foo
, sotemplate<class<class > class C> struct foo<C>;
is not a partial specialization of templatefoo
.这篇关于可变参数模板样板参数可以部分专业化吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
-