c – 初始化期间的lambda捕获应该是一个错误

我正在尝试做的是在构造可能无效的对象时吃异常.它非常适合使用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 {};
  }();
}

Compiler exited with result code 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 {};
  }();
}

error: variable ‘foo’ declared with ‘auto’ type cannot appear in its own initializer

请注意,我在Ubuntu 16.04 LTS上使用GCC 6.2发现了这一点. Godbolt中的配置使用了clang 3.9.1.两者都配置为c 14.

所以我的问题是:

>为什么lambda捕获初始化非自动声明的变量能够捕获并使用(尚未初始化的)变量?
>为什么自动获取(在我看来,正确)被捕获和错误?
>而且,为什么上述两者之间存在差异?这听起来像编译器错误,但是…标准中有哪些特定的声明这是正确的行为?
>这可以作为auto关键字的参数?

最佳答案 第二个片段运行到 [dcl.spec.auto]/10:

If the type of an entity with an undeduced placeholder type is needed
to determine the type of an expression, the program is ill-formed.

需要foo的类型来确定lambda体内表达式foo的类型,但是那时你还没有推导出foo的类型,所以程序是不正确的.

至于为什么允许你在初始化之前捕获一些东西,一般参见Why is ‘int i = i;’ legal?.我们有许多使用std :: function的递归lambdas的例子:

std::function<void(int)> foo = [&foo](int i){ return foo(i - 1); };
点赞