gpt4 book ai didi

c++ - lambda : GCC bug and/or Clang bug? 中捕获变量的 decltype()

转载 作者:可可西里 更新时间:2023-11-01 15:22:58 28 4
gpt4 key购买 nike

我检查了 GCC buglistClang buglist并且还没有看到任何相关内容。

This Wandbox link显示一些 C++11/C++14 代码为各种类型的 x 执行 decltype(x)decltype((x))被 lambda 捕获。 GCC 和 Clang 对这段代码给出了不同的答案。如果有的话,哪一个是正确的?

这是有问题的片段:

// inside main()
int i = 42;
int &j = i;
[j=j](){
static_assert(std::is_same<decltype(j), GCC(const) int>::value,""); // A
static_assert(std::is_same<decltype((j)), const int&>::value,""); // B
}();
[=](){
static_assert(std::is_same<decltype(j), int&>::value,""); // C
static_assert(std::is_same<decltype((j)), CLANG(const) int&>::value,""); // D
}();

哪里:

#ifdef __clang__
#define CLANG(x) x
#define GCC(x)
#else
#define GCC(x) x
#define CLANG(x)
#endif

我相信在这两种情况下,实际捕获的东西(*) 是一个(非常量)int 初始化为 j 的拷贝的值(也就是i的值)。由于 lambda 未标记为 mutable,因此其 operator() 将成为 const 成员函数。有了这些先决条件,让我们继续……

在线 //A,GCC 告诉我显式初始化捕获的 j 的 decltype 是 const int,当我'我几乎肯定它应该是 int(根据 Clang)。

//B 行,两个编译器都同意 (j) 是一个引用 const int 的左值(因为 lambda 没有标记为 mutable);这对我来说非常有意义。

//C 行,两个编译器都同意 j 是引用第 2 行声明的 int& 的名称。这是一个5.1.2 [expr.prim.lambda]/19 的结果,或者更确切地说,当那个子句被调用时发生的事情的结果。在 [=] lambda 中,name j 指的是外部作用域中的 j,但是 < em>expression (j) 指的是 (j) 如果 j 被捕获,则该 (j) 将存在。我不完全理解它是如何工作的或者为什么它是可取的,但就是这样。我愿意声明这不是任何一个编译器中的错误。

//D 行,Clang 告诉我 (j) 是一个指代 const int 的左值,而 GCC 告诉我它是一个指代 a 的左值非常量 int。我很确定 Clang 是对的,而 GCC 是错的; decltype((j)) 应该是相同的,无论 j 是隐式捕获还是显式捕获。

所以:

  • 我的解释是否正确(根据标准)?
  • C++11 和 C++14(以及 C++1z)之间的正确答案是否有变化?
  • //A//D 都是 GCC 中的错误吗?
  • 这些错误是否已提交?

(*) — 事实上,第二个 lambda 在技术上没有捕获,因为它在任何评估的上下文中都没有使用 j .这就是 //A//C 行给出不同答案的原因。但是我不知道什么好用的术语来形容那件事--被完成-j,所以我只是说“捕获”。

最佳答案

我相信 两个编译器对于 (A) 都是错误的,而 gcc 对于 (D) 是错误的。
我认为 gcc 对于 (A) 和 (D) 是错误的,而 clang 对于两者都是正确的。


[expr.lambda.prim] 的相关部分是:

An init-capture behaves as if it declares and explicitly captures a variable of the form “auto init-capture ;” whose declarative region is the lambda-expression’s compound-statement, except that:
— if the capture is by copy (see below), the non-static data member declared for the capture and the variable are treated as two different ways of referring to the same object, which has the lifetime of the non-static data member, and no additional copy and destruction is performed,

Every id-expression within the compound-statement of a lambda-expression that is an odr-use (3.2) of an entity captured by copy is transformed into an access to the corresponding unnamed data member of the closure type.

decltype(j) 不是 j 的 ODR 使用,因此不应考虑此类转换。因此,在 [=]{...} 的情况下,decltype(j) 应该产生 int&。然而,在 init-capture 的情况下,行为就好像有一个 auto j = j; 形式的变量,而变量 j 引用相同的未命名非静态数据成员,无需进行此类转换。所以在 [j=j]{...} 的情况下,decltype(j) 应该产生该变量的类型 - 即 int。它绝对不是 const int。这是一个错误。

下一个相关部分:

Every occurrence of decltype((x)) where x is a possibly parenthesized id-expression that names an entity of automatic storage duration is treated as if x were transformed into an access to a corresponding data member of the closure type that would have been declared if x were an odr-use of the denoted entity. [ Example:

void f3() {
float x, &r = x;
[=] { // x and r are not captured (appearance in a decltype operand is not an odr-use)
decltype(x) y1; // y1 has type float
decltype((x)) y2 = y1; // y2 has type float const& because this lambda
// is not mutable and x is an lvalue
decltype(r) r1 = y1; // r1 has type float& (transformation not considered)
decltype((r)) r2 = y2; // r2 has type float const&
}
}

—end example ]

该示例进一步说明了 decltype(j) 在隐式复制情况下应该是 int& 并且还演示了 decltype((j)) 被视为好像 x 是将被声明的相应数据成员:在这两种情况下都是 int const&(因为 lambda 不是 mutablej 是一个左值)。您的 (C) 和 (D) 案例完全反射(reflect)了示例中的 r1r2 声明。其中,虽然示例不是规范的,但肯定表明 gcc 有不同的行为是错误的。

关于c++ - lambda : GCC bug and/or Clang bug? 中捕获变量的 decltype(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31040915/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com