lll*_*lll 17 c++ templates clang template-specialization language-lawyer
考虑以下程序:
template<template<typename ...> class>
struct foo {};
template<template<typename> class C>
struct foo<C> {};
int main() {}
Run Code Online (Sandbox Code Playgroud)
Clang拒绝了它的错误:
类模板部分特化不会专门化任何模板参数
即使在最新的clang 7.0 HEAD中,请参见此处的演示.但是,gcc接受了它.
请参阅[temp.class.spec],其中陈述了部分特化的规则,我找不到任何禁止该模板的部分特化的东西.特别是,专业化确实更专业,错误消息看起来不正确.
编辑:
但是,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();
}
Run Code Online (Sandbox Code Playgroud)
事实证明,gcc在这种情况下使用专用版本,请参见此处.
现在我想问:
是标准允许的这种局部专业化吗?
哪个编译器是正确的?(一个/全部/没有?)
这最终似乎是新的 C++ 模板模板参数推导部分支持此功能的实现中的一个 GCC 错误。
为了确定部分特化是否比类模板更特化,将部分排序应用于 2 个相应的综合函数:
//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>);
Run Code Online (Sandbox Code Playgroud)
然后尝试通过使用与另一个函数参数相对应的参数调用每个函数来执行模板参数推导(请参阅[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>{});
Run Code Online (Sandbox Code Playgroud)
如果模板参数对于 (1) 成功,则至少与f_foo_partial一样专业化。如果模板参数在 (2) 中成功,则至少与. (参见[temp.deduct.partial] )一样专业化。那么,如果只有一个至少与另一个一样专业,那么它就是更专业的一个。f_foof_foof_foo_partial
因此,要检查模板参数是否可扣除,则执行从类型中扣除模板参数的操作。
然后,为了执行此匹配,应用 C++17 中引入的规则[temp.arg.template]/3:
当 P 至少与模板参数 A 一样专业时,模板参数与模板参数 P 匹配。[...]
[temp.arg.template]/4 指定将使用这些发明的两个函数与前面的情况类似地执行此排序:
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>{});
Run Code Online (Sandbox Code Playgroud)
for (1) 模板参数继承 AType` 的推导参数...P`` is。
对于 (2),有一条特殊规则,仅适用于模板部分排序 [temp.deduct.type]/9.2 的情况:
[...]在部分订购期间,如果 Ai 最初是一个包扩展:
如果 P 不包含与 Ai 对应的模板参数,则忽略 Ai;
否则,如果 Pi 不是包展开,则模板参数推导失败。
这里 Ai 是ATypePack且Pi是 的P函数参数中的 template<class P> void p_foo_partial(foo<P>)。
因此,由于粗体引用的这条规则,模板参数推导对于(2)失败,因此模板模板参数“class P”比它的参数更特殊。所以这个调用f_foo_partial(foo<ATypePack>{})是正确的。
另一方面,相同的规则,f_foo(AType{})由于 [temp.arg.temp]/3,对 的调用格式良好:
[...] 如果 P 包含参数包,则如果 A 的每个模板参数与 P 的模板参数列表中相应的模板参数匹配,则 A 也与 P 匹配。[...]
sof_foo_partial并不比 template 更专业化f_foo,所以template<class<class > class C> struct foo<C>;不是 template 的部分专业化foo。
| 归档时间: |
|
| 查看次数: |
575 次 |
| 最近记录: |