[英]Why visual c++ (latest) and gcc 12.1 accepted hiding this init capture for lambda, while clang 14.0.0 not? (c++20)
Case 1情况1
int main() {
int x = 100;
auto lamb_var = [y = x](){
int y = 10;
return y + 1;
};
assert (lamb_var() == 11);
return 0;
}
in https://godbolt.org/z/hPPParjnz在https://godbolt.org/z/hPPParjnz
Both MSVC and GCC accepted shadowing the init-capture, while Clang accused y redefinition on the compound statement and throwed compiler error. MSVC 和 GCC 都接受了对 init-capture 的遮蔽,而 Clang 指责 y 在复合语句上重新定义并引发编译器错误。
However, if we remove the init-capture and make a simple-capture, all compilers accept Shadowing:但是,如果我们删除 init-capture 并进行 simple-capture,所有编译器都接受 Shadowing:
Case 2案例2
int main() {
int x = 100;
auto lamb_var = [x](){
int x = 10;
return x + 1;
};
assert (lamb_var() == 11);
return 0;
}
in https://godbolt.org/z/Gs4cadf5e在https://godbolt.org/z/Gs4cadf5e
A simple-capture (case 2) leads to the creation of an attribute in the lambda-associated class, so shadowing should be normal.简单捕获(案例 2)导致在 lambda 关联的 class 中创建属性,因此阴影应该是正常的。
From what I found,the expression "whose declarative region is the body of the lambda expression" of the quote below from cppreference could defend the implementation of CLANG ("redefinition"), but I'm not sure.根据我的发现,cppreference 下面引用的“其声明区域是 lambda 表达式的主体”的表达式可以捍卫 CLANG (“重新定义”)的实现,但我不确定。
A capture with an initializer acts as if it declares and explicitly captures a variable declared with type auto, whose declarative region is the body of the lambda expression (that is, it is not in scope within its initializer), except that: [...] [1]带有初始化程序的捕获就像它声明并显式捕获了一个声明为 auto 类型的变量,其声明区域是 lambda 表达式的主体(也就是说,它不在其初始化程序中的 scope 中),除了: [.. .] [1]
Who is right in implementation (GCC and MSVC or Clang), and how to understand this citation of cppreference?谁在实施中是正确的(GCC 和 MSVC 或 Clang),以及如何理解对 cppreference 的引用?
[1] < https://en.cppreference.com/w/cpp/language/lambda > [1] < https://en.cppreference.com/w/cpp/language/lambda >
I think that clang is correct in rejecting snippet 1 and accepting snippet 2 because in the first case the non-static data member is named y
while in the second case the non-static data member is unnamed .我认为clang 拒绝片段 1 并接受片段 2 是正确的,因为在第一种情况下,非静态数据成员被命名为y
而在第二种情况下,非静态数据成员被命名为unnamed 。
Here we consider snippet 1:这里我们考虑片段 1:
int main() {
int x = 100;
auto lamb_var = [y = x](){ //the data member is "named" y
int y = 10; //error because we're defining y for second time
return y + 1;
};
assert (lamb_var() == 11);
return 0;
}
Now, from expr.prim.lambda#capture-6 :现在,从expr.prim.lambda#capture-6 :
An init-capture without ellipsis behaves as if it declares and explicitly captures a variable of the form
auto init-capture;
没有省略号的 init-capture表现得好像它声明并显式捕获了auto init-capture;
whose declarative region is the lambda-expression's compound-statement , except that:其声明区域是 lambda 表达式的复合语句,除了:
(emphasis mine) (强调我的)
This seems to indicate that the non-static data member has a name which in your given example is y
.这似乎表明非静态数据成员的名称在您给定的示例中为y
。 Now, by writing int y = 10;
现在,通过写int y = 10;
we're providing a redefinition of the same named variable y
in the same declarative region and hence the error.我们在同一声明区域中提供了相同命名变量y
的重新定义,因此出现了错误。
Note that we will get the same error(as expected due to the reason explained above), if we replace [y=x]
with [x=x]
and int y =10;
请注意,如果我们将[y=x]
替换为[x=x]
并且int y =10;
我们将得到相同的错误(由于上述原因)。 with int x = 10;
与int x = 10;
as shown below:如下所示:
int main() {
int x = 100;
auto lamb_var = [x = x](){ //data member "named" x
int x = 10; //this will give same error
return x + 1;
};
assert (lamb_var() == 11);
return 0;
}
Here we consider the second snippet:这里我们考虑第二个片段:
int main() {
int x = 100;
auto lamb_var = [x](){ //data member is unnamed
int x = 10; //ok because we're defining an int variable with "name" x for the first time in this region
return x + 1;
};
assert (lamb_var() == 11);
return 0;
}
Here from expr.prim.lambda#capture-10 :这里来自expr.prim.lambda#capture-10 :
For each entity captured by copy, an unnamed non-static data member is declared in the closure type.对于通过副本捕获的每个实体,在闭包类型中声明了一个未命名的非静态数据成员。 The declaration order of these members is unspecified....这些成员的声明顺序不详......
(emphasis mine) (强调我的)
In this case, the non-static data member is unnamed and so writing int x = 10;
在这种情况下,非静态数据成员未命名,因此写作int x = 10;
is not a redefinition error because we're definining a variable named x
for the first time in this region.不是重新定义错误,因为我们在该区域中首次定义了一个名为x
的变量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.