初始化期间的 lambda 捕获应该是一个错误
Posted
技术标签:
【中文标题】初始化期间的 lambda 捕获应该是一个错误【英文标题】:lambda capture during initialization should be an error 【发布时间】:2017-08-20 12:29:13 【问题描述】:我正在尝试做的是在构造一个可能无效的对象时吃异常。它非常适合使用std::optional
,但我不相信std::optional
的省略会改变我看到的错误:对象在初始化之前被捕获和使用。我不认为应该首先捕获它,因为据我所知,我们还没有达到 序列点(lambda 初始化算作序列点吗?)。此外,该错误是 IMO 很容易捕获的人为错误(甚至会被捕获……视情况而定)。
lambda 如何(更重要的是,为什么)能够捕获和使用尚未初始化的foo
?
https://godbolt.org/g/IwcHrV
#include <string>
using namespace std;
void foo()
string foo = [&]()->string
// using foo before it's been initialized == undefined behavior
auto guessed_foo = to_string(1234);
if ( begin(foo) == end(foo) )
return guessed_foo;
return ;
();
编译器退出,结果代码为 0
但是...用auto foo
替换string foo
的声明确实 似乎会导致类似于我希望看到的错误。
https://godbolt.org/g/GfE4WH
#include <string>
using namespace std;
void foo()
auto foo = [&]()->string
auto guessed_foo = to_string(1234);
if ( begin(foo) == end(foo) )
return guessed_foo;
return ;
();
错误:用 'auto' 类型声明的变量 'foo' 不能出现在它自己的初始化程序中
请注意,我在 Ubuntu 16.04 LTS 上使用 GCC 6.2 发现了这一点。 Godbolt 中的配置使用的是 clang 3.9.1。两者都是为 c++14 配置的。
所以我的问题是:
为什么用于初始化非自动声明变量的 lambda 捕获能够捕获和使用(尚未初始化的)变量? 为什么auto
会(在我看来是正确的)被捕获并出错?
而且,为什么以上两者有区别?听起来像是编译器错误,但是……标准中是否有特定内容声明这是正确的行为?
这可以作为参数 for auto
关键字?
【问题讨论】:
高度相关:***.com/questions/11186261/why-is-int-i-i-legal 【参考方案1】:第二个sn-p跑到[dcl.spec.auto]/10:
如果需要具有未推断占位符类型的实体类型 要确定表达式的类型,程序是非良构的。
需要 foo
的类型来确定 lambda 主体中表达式 foo
的类型,但此时您还没有推断出 foo
的类型,因此程序是非良构的.
至于为什么允许在初始化之前捕获某些内容,请参阅Why is 'int i = i;' legal?。我们有很多使用 std::function
的递归 lambda 示例:
std::function<void(int)> foo = [&foo](int i) return foo(i - 1); ;
【讨论】:
好的,那么为什么-Winit-self -Wuninitialized
会发出int i = i;
的诊断信息,但 not 来自 lambda 表达式? godbolt.org/g/qC2iao
@inetknght 这些是尽力而为的警告,不能保证。以上是关于初始化期间的 lambda 捕获应该是一个错误的主要内容,如果未能解决你的问题,请参考以下文章
在嵌套 lambda 的情况下如何初始化 lambda 捕获?