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

时间:2017-03-27 17:07:54

标签: c++ lambda initialization c++14

尝试做的是在构造可能无效的对象时吃异常。它对于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

但是......用string foo 替换auto 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(在我看来,正确地)得到了错误?
  • 而且,为什么上述两者之间存在差异?这听起来像编译器错误,但是......标准中是否有特定的内容声明这是正确的行为?
  • 这可以作为参数 auto关键字?

1 个答案:

答案 0 :(得分:2)

第二个代码段会遇到[dcl.spec.auto]/10

  

如果需要具有未减少占位符类型的实体的类型   为了确定表达式的类型,程序是不正确的。

需要foo的类型来确定lambda体内表达式foo的类型,但此时您还没有推断foo&#39; s类型,所以该程序是不正确的。

关于为什么允许在初始化之前捕获某些内容,请参阅Why is 'int i = i;' legal?。我们有很多使用std::function递归lambda的例子:

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