使用未扩展的参数包作为模板模板参数的非类型模板参数的类型是否合法?

发布于 2025-01-13 13:36:29 字数 881 浏览 0 评论 0原文

gcc 和 clang 对于以下代码是否应该编译存在分歧:

template <typename... Args>
struct tuple {};

template <typename>
struct Test;

template <
    typename... Types,
    template <Types> typename... Outer, // XXX
    Types... Inner
>
struct Test<tuple<Outer<Inner>...>> {};

template <long T> struct O1 {};
template <unsigned T> struct O2 {};

Test<tuple<O1<1>, O2<2>>> test;

clang 接受代码,推导出 Types = {long, unsigned}, Outer = {O1, O2}, Inner={1L, 2U}。从结构上看,这似乎是正确的。

gcc 因推导失败而拒绝该代码。有趣的是,如果将 O2 更改为采用 long 非类型模板参数,它确实接受,这对我来说似乎不一致。它表明如果 Types = {long, long} 则可以扩展 Types,但如果 Types = {long, unsigned} 则不能扩展。

但是,从标准中我不清楚哪个编译器是正确的。核心问题是:在XXX这一行,模板参数的非类型模板参数的类型为参数包是否有效?它应该像 clang 声称的那样扩展吗?

gcc and clang disagree about whether the following code should compile:

template <typename... Args>
struct tuple {};

template <typename>
struct Test;

template <
    typename... Types,
    template <Types> typename... Outer, // XXX
    Types... Inner
>
struct Test<tuple<Outer<Inner>...>> {};

template <long T> struct O1 {};
template <unsigned T> struct O2 {};

Test<tuple<O1<1>, O2<2>>> test;

clang accepts the code, deducing Types = {long, unsigned}, Outer = {O1, O2}, Inner={1L, 2U}. Structurally, this seems correct.

gcc rejects the code with a deduction failure. Interestingly, it does accept if O2 is changed to take a long non-type template parameter, which seems inconsistent to me. It suggests that Types can be expanded if Types = {long, long} but not if Types = {long, unsigned}.

However, it's not clear to me from the standard which compiler is correct. The core question is: on the line denoted XXX, is it valid to have a parameter pack as the type of the template template parameter's non-type template parameter? Should it expand the way that clang claims it does?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

叫思念不要吵 2025-01-20 13:36:30

无效,因为:

类型参数包不能在其自己的参数子句中扩展。

[temp.param]/17 开始:

如果模板参数是一个类型参数,其可选标识符之前有省略号,或者是一个参数-声明声明了一个包([dcl.fct]),那么template-parameter就是一个模板参数包。模板参数包是一个参数声明,其类型包含一个或多个未扩展的包,这是一个包扩展。 ... 作为包扩展的模板参数包不得扩展在同一模板参数列表中声明的模板参数包。

因此,请考虑以下无效示例:

template<typename... Ts, Ts... vals> struct mytuple {}; //invalid

上面的示例无效,因为模板类型参数包Ts无法在其自己的参数列表中扩展。

出于同样的原因,您的代码示例无效。

It is not valid because:

a type parameter pack cannot be expanded in its own parameter clause.

As from [temp.param]/17:

If a template-parameter is a type-parameter with an ellipsis prior to its optional identifier or is a parameter-declaration that declares a pack ([dcl.fct]), then the template-parameter is a template parameter pack. A template parameter pack that is a parameter-declaration whose type contains one or more unexpanded packs is a pack expansion. ... A template parameter pack that is a pack expansion shall not expand a template parameter pack declared in the same template-parameter-list.

So consider the following invalid example:

template<typename... Ts, Ts... vals> struct mytuple {}; //invalid

The above example is invalid because the template type parameter pack Ts cannot be expanded in its own parameter list.

For the same reason, your code example is invalid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文