Man*_*uel 6 c++ lambda compiler-errors language-lawyer
情况1
int main() {
int x = 100;
auto lamb_var = [y = x](){
int y = 10;
return y + 1;
};
assert (lamb_var() == 11);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在https://godbolt.org/z/hPPParjnz
MSVC 和 GCC 都接受隐藏 init-capture,而 Clang 则指责复合语句上的 y 重新定义并引发编译器错误。
但是,如果我们删除 init-capture 并进行 simple-capture,则所有编译器都接受 Shadowing:
案例2
int main() {
int x = 100;
auto lamb_var = [x](){
int x = 10;
return x + 1;
};
assert (lamb_var() == 11);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在https://godbolt.org/z/Gs4cadf5e
简单捕获(情况 2)会导致在 lambda 关联类中创建属性,因此阴影应该是正常的。
根据我的发现,下面引用 cppreference 的表达式“其声明区域是 lambda 表达式的主体”可以捍卫 CLANG 的实现(“重新定义”),但我不确定。
使用初始值设定项的捕获的行为就像它声明并显式捕获使用类型 auto 声明的变量一样,其声明区域是 lambda 表达式的主体(即,它不在其初始值设定项的范围内),除了: [.. .]
谁在实现上是正确的(GCC 和 MSVC 还是 Clang),以及如何理解 cppreference 的引用?
相关问题
我认为clang 拒绝片段 1 和接受片段 2 是正确的,因为在第一种情况下,非静态数据成员被命名 y,而在第二种情况下,非静态数据成员是unnamed。
这里我们考虑片段 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;
}
Run Code Online (Sandbox Code Playgroud)
现在,来自expr.prim.lambda#capture-6:
不带省略号的 init-capture 的行为就好像它声明并显式捕获其声明区域是 lambda 表达式的 复合语句形式的变量 ,但以下情况除外:
auto init-capture ;
(强调我的)
这似乎表明非静态数据成员的名称在您给定的示例中为y。现在,通过编写,int y = 10;我们y在同一声明区域中提供了对同一命名变量的重新定义,从而导致了错误。
[y=x]请注意,如果我们用 和[x=x]with替换,我们将得到相同的错误(由于上述原因,正如预期的那样),int y =10;如下int x = 10; 所示:
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;
}
Run Code Online (Sandbox Code Playgroud)
这里我们考虑片段 2:
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;
}
Run Code Online (Sandbox Code Playgroud)
来自expr.prim.lambda#capture-10:
对于复制捕获的每个实体,在闭包类型中声明一个未命名的非静态数据成员。这些成员的声明顺序未指定......
(强调我的)
在这种情况下,非静态数据成员是未命名的,因此写入int x = 10;不是重新定义错误,因为我们正在该区域中第一次定义一个命名的变量。 x
| 归档时间: |
|
| 查看次数: |
147 次 |
| 最近记录: |