提问人:Constantinos Glynos 提问时间:2/21/2018 最后编辑:Jarod42Constantinos Glynos 更新时间:3/13/2023 访问量:387
Clang 与 G++ 在类模板参数数量和模板模板参数重新声明方面存在分歧
Clang vs G++ disagree on class template number of arguments and template template parameter redeclaration
问:
在下面的示例中,是一个类模板,其第一个参数是类型,第二个参数是另一个模板,该模板采用布尔值和任意数量的参数。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 就在这里,因为第三个专用化对模板模板参数有效,而可变参数模板参数允许我专用于任意数量的参数。但是,我不确定。
问题:哪个编译器是有缺陷的编译器?为什么?如果能从规范中得到报价并更清楚地了解该主题,那就太好了。
答:
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 ...> class
template<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.
评论