Clang vs G ++对类模板的参数数量和模板模板参数重新声明不一致

Con*_*nos 7 c++ templates language-lawyer c++14

在下面的示例中,Abstract是一个类模板,其第一个参数是一个类型,第二个参数是另一个模板,它带有一个bool以及任意数量的args.

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()
{}
Run Code Online (Sandbox Code Playgroud)

Clang和C++的输出如下:

Clang: http ://rextester.com/BJSW46677

错误:类模板部分特化没有专门化任何模板参数;

G ++ http://rextester.com/MDN65674

所以,我决定对clang友好,并在Abstract声明中添加了第三个参数.

template< typename T = void,
          template<bool,typename ...> class = Default,
          typename = void >
struct Abstract;
Run Code Online (Sandbox Code Playgroud)

现在,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()
{}
Run Code Online (Sandbox Code Playgroud)

Clang和C++的输出如下:

Clang: http ://rextester.com/LJIOC38789

错误:重新定义Abstract<type-parameter-0-0, C, void>注释:以前的定义是struct Abstract<T,C> : Abstract<T>

G ++: http ://rextester.com/TSDRZ44717

好的 - (也不需要声明中的第三个参数)

不认为 Clang就在这里,因为第三个专门化对模板模板参数有效,并且variadic模板参数允许我专门用于任意数量的参数.但是,我不确定.

问题:哪个编译器是错误的?为什么?从规范中获得一个引用并且对该主题更加清晰是非常好的.

Bri*_*ian 1

正如评论中指出的,问题的第一部分\xe2\x80\x94,即是否允许专门研究作为主模板\xe2\x80\x94 中的可变参数模板的模板模板参数本质上是与另一个问题相同。如果您阅读了我对该问题的回答,它包含了部分专业化的部分排序规则如何工作的摘要。特别是在您的情况下,问题是从 C++17 开始,template<bool,typename ...> class参数可以接受template<bool> class参数,反之亦然;这意味着在 C++17 及更高版本中,部分排序规则得出的结论是您编写的部分特化并不比主模板更特化,这使得程序格式错误。

\n

(FWIW,Godbolt 上可用的最新版本的 Clang trunk 接受专业化,我希望 CWG2398 最终能够以一种使该代码格式良好的方式得到解决。)

\n

至于你的问题的第二部分,关于一对部分专业化:

\n
template<typename T, template<bool> class C>\nstruct Abstract<T,C> : Abstract<T>\n{};\n\ntemplate<typename T, template<bool,typename> class G>\nstruct Abstract<T,G> : Abstract<T>\n{};\n
Run Code Online (Sandbox Code Playgroud)\n

Clang 的某些版本声称第二个版本是第一个版本的“重新声明”,这纯粹是无稽之谈;这可能是这些版本中的一个错误。这是固定在行李箱中的。

\n