在下面的例子中,
Abstract
是一个类模板,它的第一个参数是一个类型,第二个参数是另一个带有布尔值和任意数量的参数的模板。
template<bool,typename>
struct Default;
template< typename T = void,
template<bool,typename ...> class = Default>
struct Abstract;
template<typename T>
struct Abstract<T>
{};
template<typename T, template<bool> class C>
struct Abstract<T,C> : Abstract<T>
{};
int main()
{}
Clang 和 C++ 的输出如下:
铿锵声: http://rextester.com/BJSW46677
错误:类模板部分特化不特化任何 模板参数;
G++http://rextester.com/MDN65674
好
所以,我决定对 clang 友好,并在
Abstract
的声明中添加了第三个参数。
template< typename T = void,
template<bool,typename ...> class = Default,
typename = void >
struct Abstract;
现在,Clang 和 G++ 都可以解决这个问题。我猜 Clang 抱怨的原因是因为专业化并没有真正专业化任何东西。但事实并非如此。它专门针对参数的数量。
接下来,我为模板模板参数添加了另一个特化。这个例子看起来像这样:
template<bool,typename>
struct Default;
template< typename T = void,
template<bool,typename ...> class = Default,
typename = void >
struct Abstract;
template<typename T>
struct Abstract<T>
{};
template<typename T, template<bool> class C>
struct Abstract<T,C> : Abstract<T>
{};
template<typename T, template<bool,typename> class G>
struct Abstract<T,G> : Abstract<T>
{};
int main()
{}
Clang 和 C++ 的输出如下:
铿锵声: http://rextester.com/LJIOC38789
错误:
的重新定义注意:以前的定义是Abstract<type-parameter-0-0, C, void>
struct Abstract<T,C> : Abstract<T>
G++: http://rextester.com/TSDRZ44717
OK -(声明中也不需要第三个参数)
我 不认为 Clang 就在这里,因为第三个特化对模板模板参数有效,可变模板参数允许我特化任意数量的参数。但是,我不确定。
问题: 哪个编译器有问题?为什么?如果能从规范中引用并更清楚地了解这个主题,那就太好了。
正如评论中所指出的,问题的第一部分——即是否允许专注于主模板中作为可变参数模板的模板模板参数——与另一个问题基本相同。如果您阅读了我对那个问题的回答,它包含了偏特化的偏序规则如何工作的摘要。特别是在您的情况下,问题是自 C++17 以来,
template<bool,typename ...> class
参数可以接受 template<bool> class
参数,反之亦然;这意味着在 C++17 及更高版本中,偏序规则得出的结论是您编写的偏特化 not 比主模板更特化,这使得程序格式错误。
(FWIW,Godbolt 上可用的最新版本的 Clang trunk 接受专业化,我希望 CWG2398 最终能够以一种使这段代码格式良好的方式得到解决。)
关于问题的第二部分,关于一对偏专业:
template<typename T, template<bool> class C>
struct Abstract<T,C> : Abstract<T>
{};
template<typename T, template<bool,typename> class G>
struct Abstract<T,G> : Abstract<T>
{};
某些版本的 Clang 声称第二个版本是第一个版本的“重新声明”简直是无稽之谈;这可能是那些版本中的错误。这是固定在行李箱中的。