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

Clang vs G++ disagree on class template number of arguments and template template parameter redeclaration

提问人:Constantinos Glynos 提问时间:2/21/2018 最后编辑:Jarod42Constantinos Glynos 更新时间:3/13/2023 访问量:387

问:

在下面的示例中,是一个类模板,其第一个参数是类型,第二个参数是另一个模板,该模板采用布尔值和任意数量的参数。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++ 模板 C++14 语言律师

评论

2赞 Nikita Kniazev 2/21/2018
你问题的本质就在这个问题中 stackoverflow.com/questions/48893928/......
0赞 Constantinos Glynos 2/21/2018
@NikitaKniazev 请纠正我,但我相信你提到的问题谈到了主要可变参数模板及其专业化之间的歧义。顺便说一句,我不认为这是一个模棱两可。C++模板 - 完整指南第2版,p351说:“此外,显式编写的模板参数的数量甚至可能与主模板中的模板参数数量不同。这既可以发生在默认模板参数上,也可以以一种更有用的方式发生在可变参数模板上。还有一个例子,不适合评论。
0赞 Nikita Kniazev 2/21/2018
您(就像我链接的问题一样)尝试通过模板模板类进行专用化,并假设当编译器尝试为部分专用化找到最佳匹配项时,会考虑模板模板类中的模板参数数量。
0赞 Constantinos Glynos 2/22/2018
@NikitaKniazev对不起..这变得非常有压力。我只是把下面的例子通过godbolt来看看编译器是做什么的,一切似乎都还好(godbolt.org/g/4K6euj)。另外,请看一下这个 textester 示例 ( rextester.com/KYZ39240 )。如果这是一个 G++ 错误,那么它就是一个快乐的错误。但我不明白为什么专业化会格式不正确!它是否在 C++ 标准的某个地方明确提到?
0赞 Constantinos Glynos 2/22/2018
@NikitaKniazev Furhtermore,我在 C++ Templates 书籍第 2 版中发现了这一点:“可变参数模板参数是上述 C++17 之前的”完全匹配“规则的例外,并为此限制提供了解决方案:它们支持对模板模板参数进行更通用的匹配。模板模板参数包可以匹配模板模板参数中的零个或多个同类模板参数”。这意味着专业化并非格式错误。这本书还展示了一个与我在之前的评论中发送的类似的示例。我认为 G++ 在这种情况下做对了。

答:

1赞 Brian Bi 3/13/2023 #1

As pointed out in the comments, the first part of the question—namely, whether it's allowed to specialize on a template template argument that is a variadic template in the primary template—is essentially the same as this other question. If you read my answer to that question, it contains a summary of how the partial ordering rules for partial specializations work. In your case in particular, the problem is that since C++17, a parameter can accept a argument and vice versa; that means that in C++17 and later, the partial ordering rules come to the conclusion that the partial specialization you wrote is not more specialized than the primary template, which makes the program ill-formed.template<bool,typename ...> classtemplate<bool> class

(FWIW, the latest version of Clang trunk available on Godbolt accepts the specialization, and I would expect CWG2398 to be eventually resolved in a way that makes this code well-formed.)

As for the second part of your question, regarding the pair of partial specializations:

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>
{};

the claim by some versions of Clang that the second one is a "redeclaration" of the first one is simply nonsense; it is presumably a bug in those versions. This is fixed in trunk.