【问题标题】:`decltype` of generalized lambda capture inside body of a lambda - gcc vs clang在 lambda 体内捕获广义 lambda 的`decltype` - gcc vs clang
【发布时间】:2020-11-07 20:02:19
【问题描述】:

考虑以下代码:

#include <type_traits>

int main()
{
    auto l = [k = 0]
    {
        static_assert(std::is_same_v<decltype(k), int>);
    };
}
  • clang++(10.x 和trunk)愉快地编译了上面的代码。

  • g++(10.x 和trunk)无法编译上面的代码并出现以下错误:

    error: static assertion failed
       10 |         static_assert(std::is_same_v<decltype(k), int>);
          |                       ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~
    

    显然,g++ 认为 decltype(k) 的计算结果为 const int。

live example on godbolt.org

由于数据成员k的类型应该是从0推导出来的(这是一个普通的,非const,int),我认为这是一个g++的bug。在我的心智模型中,唯一的 const 是 lambda 的 operator(),而不是合成数据成员 k。

  • 我的评估是否正确?

  • 标准是怎么说的?

【问题讨论】:

  • 如果有帮助,clang 编译 static_assert(std::is_same_v&lt;decltype(i), Foo&gt;); 和 gcc 编译 static_assert(std::is_same_v&lt;decltype(i), const Foo&gt;); 所以我不认为这是 int i; 的问题。
  • 据我所知,该语言只要求不得修改k。我猜想通过使合成成员 const (正如 gcc 似乎正在做的那样)来实现这一点是允许的,所以两者都是正确的。
  • @cigien Not so sure about that。在大多数情况下,该标准煞费苦心地将 lambda 体内变量的出现视为实际上“直接”指代封闭范围内的事物,而不是闭包类型的成员。显然,初始化捕获也是如此。

标签: c++ lambda c++14 language-lawyer shadowing


【解决方案1】:

在这种情况下,标准相当明确。 [expr.prim.lambda.capture]/6:

一个没有省略号的 init-capture 表现得好像它声明并显式捕获了一个“auto init-capture ;”形式的变量,其声明区域是 lambda-expression' s 复合语句, [...]

所以您的代码(大致 - 请参阅上面引用的其余部分以了解两者有何不同)等同于以下代码,gcc accepts!:

auto k = 0;
auto l = [k]
{
    static_assert(std::is_same_v<decltype(k), int>);
};

那么谁是对的?为此,我们看到k 的类型,即int,因为auto 推导出int 为0。

那么只需查看[dcl.type.decltype]/1.3 即可:

[...] 如果 E [decltype] 中的表达式是一个未加括号的 id-expression [...],decltype(E) 是E命名的实体的类型。

实体k 的类型是int。所以 gcc 是错误的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-15
    • 1970-01-01
    • 2014-08-28
    • 2021-07-24
    • 2014-09-09
    • 2016-01-23
    • 2015-11-12
    • 1970-01-01
    相关资源
    最近更新 更多