考虑以下程序:
template<template<typename ...> class>
struct foo {};
template<template<typename> class C>
struct foo<C> {};
int main() {}
Clang拒绝了它的错误:
类模板部分特化不会专门化任何模板参数
即使在最新的clang 7.0 HEAD中,请参阅demo here . 但是,gcc accepts it .
请参阅[temp.class.spec],其中说明了部分特化规则,我找不到任何禁止该模板部分特化的内容 . 特别是,专业化确实是more specialized,错误消息看起来不正确 .
EDIT:
但是,gcc的行为也是异常的,请考虑以下程序:
#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在这种情况下使用专用版本,请参阅here .
现在我想问:
-
是标准允许的这种部分专业化吗?
-
哪个编译器正确? (一个/全部/没有?)
1 回答
这最终似乎是新C模板模板参数推导partial support for this feature的实现中的GCC错误 .
要确定部分特化是否比类模板更专业化,partial ordering is applied to 2 corresponding synthetized functions:
然后尝试通过使用与其他函数参数对应的参数调用每个函数来执行模板参数推导(参见[temp.func.order])
如果模板参数成功(1),那么
f_foo_partial
至少与f_foo
一样专业 . 如果模板参数成功(2),则f_foo
至少与f_foo_partial
一样专门化 . (参见[temp.deduct.partial]) . 然后,如果只有一个至少与另一个一样专业,那么它就是更专业的那个 .所以to check if template argument is deductible,然后deduction of template argument from a type正在执行 .
然后,要执行此匹配,应用C17中引入的规则[temp.arg.template]/3:
并且[temp.arg.template] / 4指定使用这些发明的两个函数将与前面的情况类似地执行此排序:
for(1)模板参数成功推导出
...P`` is
AType`的参数 .for(2)有一个特殊规则,仅适用于模板部分排序[temp.deduct.type] /9.2的情况:
这里的Ai是
ATypePack
,而Pi
是template<class P> void p_foo_partial(foo<P>)
的函数参数中的P
.因此,由于以粗体引用的此规则,模板参数推导在(2)中失败,因此模板模板参数"class P"比其参数更专业 . 所以电话
f_foo_partial(foo<ATypePack>{})
已经形成 .另一方面,相同的规则,由于[temp.arg.temp] / 3,对
f_foo(AType{})
的调用很好 .所以
f_foo_partial
并不比f_foo
更专业,所以template<class<class > class C> struct foo<C>;
不是模板foo
的部分特化 .