【问题标题】:Can a type be defined inside a template parameter list in C++?可以在 C++ 的模板参数列表中定义类型吗?
【发布时间】:2022-01-11 03:00:08
【问题描述】:

在模板struct B的以下定义中,lambda用作非类型模板参数的默认值,并且在lambda的主体中定义了一些类型A:

template <auto = []{ struct A{}; }>
struct B {};

Clang 和 MSVC 对此定义很好,但 GCC 抱怨:

错误:在模板参数列表中定义“struct&lt;lambda()&gt;::A”

演示:https://gcc.godbolt.org/z/f1dxGbPvs

哪个编译器在这里?

【问题讨论】:

  • 这应该没问题。在 lambda 中定义结构并不会阻止它成为文字类型,这足以让它用作非类型模板参数。此外,GCC 的错误信息是可疑的。这与在模板参数列表中定义类型时得到的消息相同,这是不允许的 gcc.godbolt.org/z/9PdxG8jKE 所以我认为这可能是 GCC 产生了解析错误。
  • gcc 也接受带有类型定义的独立 lambda:auto l = []{ struct A{}; }; - 所以,一种解决方法:gcc.godbolt.org/z/v1sfoqdMv

标签: c++ templates lambda language-lawyer


【解决方案1】:

[temp.param]/2 说:

类型不应在模板参数声明中定义。

鉴于此,GCC 拒绝此代码是正确的:此禁止不限于类型参数的 type-id,而是适用于模板参数声明中的任何地方。包括嵌套在 lambda 中。

这句话是由于DR 1380 (N3481) 而添加的,这表明它已经被我现在猜测的[dcl.fct]/17 暗示了:

类型不应在返回或参数类型中定义。

然而,这似乎只适用于声明的参数类型,而不适用于 initializer-clause。

另一方面,也可以将其理解为在模板参数中禁止 lambda 本身。毕竟,lambda 表达式隐式定义了一个类类型 ([expr.prim.lambda.closure]/1)。

另一方面,我们也有[expr.prim.lambda.closure]/2,它声明:

闭包类型在包含相应lambda-expression的最小块作用域、类作用域或命名空间作用域中声明。

这里的相关范围似乎是命名空间范围。这意味着应将 lambda 视为在模板参数列表之外声明其类型。但是,lambda 体内的声明也应该如此,并且应该允许问题中的定义。

就个人而言,我认为该禁令的范围似乎定义不明确是标准的缺陷。

【讨论】:

  • "我认为这是标准中的一个缺陷。" 为什么现在创建命名类型对于 C++ 程序员来说如此不可接受?给这种类型起个名字真的太过分了吗?
  • 别问我。我想这个限制是为了禁止像template &lt;typename T = struct point { int x, y; }&gt; 这样的东西。我认为在这种情况下没有什么意义。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-10
  • 1970-01-01
  • 1970-01-01
  • 2012-10-25
  • 2013-09-13
  • 1970-01-01
相关资源
最近更新 更多