Clang 与 G++ 在类模板参数数量和模板模板参数重新声明方面存在分歧

问题描述 投票:0回答:1

在下面的例子中,

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++ templates c++14 language-lawyer
1个回答
0
投票

正如评论中所指出的,问题的第一部分——即是否允许专注于主模板中作为可变参数模板的模板模板参数——与另一个问题基本相同。如果您阅读了我对那个问题的回答,它包含了偏特化的偏序规则如何工作的摘要。特别是在您的情况下,问题是自 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 声称第二个版本是第一个版本的“重新声明”简直是无稽之谈;这可能是那些版本中的错误。这是固定在行李箱中的。

© www.soinside.com 2019 - 2024. All rights reserved.